Unified · Split
| @@ -0,0 +1,82 @@ | ||
| 1 | +TARG=drawterm | |
| 2 | +CC=gcc | |
| 3 | +CFLAGS=-Iinclude -c -ggdb -D_THREAD_SAFE -pthread # not ready for this yet: -Wall | |
| 4 | +O=o | |
| 5 | +#CC=cl | |
| 6 | +#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -Iinclude -DWINDOWS | |
| 7 | +#O=obj | |
| 8 | + | |
| 9 | +OFILES=\ | |
| 10 | + main.$O\ | |
| 11 | + cpu.$O\ | |
| 12 | + readcons.$O\ | |
| 13 | + secstore.$O\ | |
| 14 | + latin1.$O\ | |
| 15 | + | |
| 16 | +LIBS=\ | |
| 17 | + kern/libkern.a\ | |
| 18 | + exportfs/libexportfs.a\ | |
| 19 | + libauthsrv/libauthsrv.a\ | |
| 20 | + libsec/libsec.a\ | |
| 21 | + libmp/libmp.a\ | |
| 22 | + libmemdraw/libmemdraw.a\ | |
| 23 | + libmemlayer/libmemlayer.a\ | |
| 24 | + libdraw/libdraw.a\ | |
| 25 | + libc/libc.a\ | |
| 26 | + kern/libkern.a\ | |
| 27 | + gui-x11/libx11.a\ | |
| 28 | + libmemdraw/libmemdraw.a\ | |
| 29 | + libdraw/libdraw.a\ | |
| 30 | + kern/libkern.a\ | |
| 31 | + libc/libc.a\ | |
| 32 | + libmemdraw/libmemdraw.a\ | |
| 33 | + libmemlayer/libmemlayer.a\ | |
| 34 | + libdraw/libdraw.a\ | |
| 35 | + libmachdep.a | |
| 36 | + | |
| 37 | +$(TARG): $(OFILES) $(LIBS) | |
| 38 | + $(CC) -pthread -o $(TARG) $(OFILES) $(LIBS) -L/usr/X11R6/lib -lX11 -ggdb | |
| 39 | + | |
| 40 | +%.$O: %.c | |
| 41 | + $(CC) $(CFLAGS) $*.c | |
| 42 | + | |
| 43 | +clean: | |
| 44 | + rm -f *.o */*.o */*.a drawterm *.a | |
| 45 | + | |
| 46 | +kern/libkern.a: | |
| 47 | + (cd kern; make) | |
| 48 | + | |
| 49 | +exportfs/libexportfs.a: | |
| 50 | + (cd exportfs; make) | |
| 51 | + | |
| 52 | +libauthsrv/libauthsrv.a: | |
| 53 | + (cd libauthsrv; make) | |
| 54 | + | |
| 55 | +libmp/libmp.a: | |
| 56 | + (cd libmp; make) | |
| 57 | + | |
| 58 | +libsec/libsec.a: | |
| 59 | + (cd libsec; make) | |
| 60 | + | |
| 61 | +libmemdraw/libmemdraw.a: | |
| 62 | + (cd libmemdraw; make) | |
| 63 | + | |
| 64 | +libmemlayer/libmemlayer.a: | |
| 65 | + (cd libmemlayer; make) | |
| 66 | + | |
| 67 | +libdraw/libdraw.a: | |
| 68 | + (cd libdraw; make) | |
| 69 | + | |
| 70 | +libc/libc.a: | |
| 71 | + (cd libc; make) | |
| 72 | + | |
| 73 | +gui-x11/libx11.a: | |
| 74 | + (cd gui-x11; make) | |
| 75 | + | |
| 76 | +#libmachdep.a: | |
| 77 | +# arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/'`; \ | |
| 78 | +# (cd gcc$$arch && make) | |
| 79 | + | |
| 80 | +libmachdep.a: | |
| 81 | + (cd posix-386; make) | |
| 82 | + | |
| @@ -0,0 +1,16 @@ | ||
| 1 | + | |
| 2 | +Win32 port Notes: | |
| 3 | + | |
| 4 | +* Issues: | |
| 5 | + | |
| 6 | + ** ownership questions on files are completely deferred by | |
| 7 | + marking them as unknown. It works for now, but probably | |
| 8 | + should be handled correctly. | |
| 9 | + | |
| 10 | + ** No performance measurements have been done. The interactive | |
| 11 | + response seems faster than old drawterm, but the i/o seems | |
| 12 | + slower. | |
| 13 | + | |
| 14 | + ** fs functions in devntfs.c need to handle conversions to/from | |
| 15 | + widechar and utf-8. | |
| 16 | + | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +extern char *argv0; | |
| 2 | +#define ARGBEGIN for((argv0? 0: (argv0=*argv)),argv++,argc--;\ | |
| 3 | + argv[0] && argv[0][0]=='-' && argv[0][1];\ | |
| 4 | + argc--, argv++) {\ | |
| 5 | + char *_args, *_argt;\ | |
| 6 | + Rune _argc;\ | |
| 7 | + _args = &argv[0][1];\ | |
| 8 | + if(_args[0]=='-' && _args[1]==0){\ | |
| 9 | + argc--; argv++; break;\ | |
| 10 | + }\ | |
| 11 | + _argc = 0;\ | |
| 12 | + while(*_args && (_args += chartorune(&_argc, _args)))\ | |
| 13 | + switch(_argc) | |
| 14 | +#define ARGEND SET(_argt);USED(_argt); USED(_argc); USED(_args);}USED(argv); USED(argc); | |
| 15 | +#define ARGF() (_argt=_args, _args="",\ | |
| 16 | + (*_argt? _argt: argv[1]? (argc--, *++argv): 0)) | |
| 17 | +#define ARGC() _argc | |
| 18 | + | |
| 19 | +#define EARGF(x) (_argt=_args, _args="",\ | |
| 20 | + (*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0))) | |
| @@ -0,0 +1,606 @@ | ||
| 1 | +/* | |
| 2 | + * cpu.c - Make a connection to a cpu server | |
| 3 | + * | |
| 4 | + * Invoked by listen as 'cpu -R | -N service net netdir' | |
| 5 | + * by users as 'cpu [-h system] [-c cmd args ...]' | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <u.h> | |
| 9 | +#include <libc.h> | |
| 10 | +#include <auth.h> | |
| 11 | +#include <fcall.h> | |
| 12 | +#include <authsrv.h> | |
| 13 | +#include <libsec.h> | |
| 14 | +#include "args.h" | |
| 15 | +#include "drawterm.h" | |
| 16 | + | |
| 17 | +#define Maxfdata 8192 | |
| 18 | +#define MaxStr 128 | |
| 19 | + | |
| 20 | +static char* getuser(void); | |
| 21 | +static void fatal(int, char*, ...); | |
| 22 | +static void catcher(void*, char*); | |
| 23 | +static void usage(void); | |
| 24 | +static void writestr(int, char*, char*, int); | |
| 25 | +static int readstr(int, char*, int); | |
| 26 | +static char *rexcall(int*, char*, char*); | |
| 27 | +static int setamalg(char*); | |
| 28 | +static char *keyspec = ""; | |
| 29 | +static AuthInfo *p9any(int); | |
| 30 | + | |
| 31 | +static int notechan; | |
| 32 | +#define system csystem | |
| 33 | +static char *system; | |
| 34 | +static int cflag; | |
| 35 | +int dbg; | |
| 36 | + | |
| 37 | +static char *srvname = "ncpu"; | |
| 38 | +static char *ealgs = "rc4_256 sha1"; | |
| 39 | + | |
| 40 | +/* message size for exportfs; may be larger so we can do big graphics in CPU window */ | |
| 41 | +static int msgsize = Maxfdata+IOHDRSZ; | |
| 42 | + | |
| 43 | +/* authentication mechanisms */ | |
| 44 | +static int netkeyauth(int); | |
| 45 | +static int netkeysrvauth(int, char*); | |
| 46 | +static int p9auth(int); | |
| 47 | +static int srvp9auth(int, char*); | |
| 48 | +static int noauth(int); | |
| 49 | +static int srvnoauth(int, char*); | |
| 50 | + | |
| 51 | +char *authserver; | |
| 52 | + | |
| 53 | +typedef struct AuthMethod AuthMethod; | |
| 54 | +struct AuthMethod { | |
| 55 | + char *name; /* name of method */ | |
| 56 | + int (*cf)(int); /* client side authentication */ | |
| 57 | + int (*sf)(int, char*); /* server side authentication */ | |
| 58 | +} authmethod[] = | |
| 59 | +{ | |
| 60 | + { "p9", p9auth, srvp9auth,}, | |
| 61 | + { "netkey", netkeyauth, netkeysrvauth,}, | |
| 62 | +// { "none", noauth, srvnoauth,}, | |
| 63 | + { nil, nil} | |
| 64 | +}; | |
| 65 | +AuthMethod *am = authmethod; /* default is p9 */ | |
| 66 | + | |
| 67 | +char *p9authproto = "p9any"; | |
| 68 | + | |
| 69 | +int setam(char*); | |
| 70 | + | |
| 71 | +void | |
| 72 | +exits(char *s) | |
| 73 | +{ | |
| 74 | + print("\ngoodbye\n"); | |
| 75 | + for(;;) osyield(); | |
| 76 | +} | |
| 77 | + | |
| 78 | +void | |
| 79 | +usage(void) | |
| 80 | +{ | |
| 81 | + fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n"); | |
| 82 | + exits("usage"); | |
| 83 | +} | |
| 84 | +int fdd; | |
| 85 | + | |
| 86 | +void | |
| 87 | +cpumain(int argc, char **argv) | |
| 88 | +{ | |
| 89 | + char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err, *secstoreserver, *s; | |
| 90 | + int fd, ms, data; | |
| 91 | + | |
| 92 | + /* see if we should use a larger message size */ | |
| 93 | + fd = open("/dev/draw", OREAD); | |
| 94 | + if(fd > 0){ | |
| 95 | + ms = iounit(fd); | |
| 96 | + if(msgsize < ms+IOHDRSZ) | |
| 97 | + msgsize = ms+IOHDRSZ; | |
| 98 | + close(fd); | |
| 99 | + } | |
| 100 | + | |
| 101 | + user = readcons("user", getenv("USER"), 0); | |
| 102 | + secstoreserver = nil; | |
| 103 | + ARGBEGIN{ | |
| 104 | + case 'a': | |
| 105 | + authserver = EARGF(usage()); | |
| 106 | + break; | |
| 107 | + case 'e': | |
| 108 | + ealgs = EARGF(usage()); | |
| 109 | + if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) | |
| 110 | + ealgs = nil; | |
| 111 | + break; | |
| 112 | + case 'd': | |
| 113 | + dbg++; | |
| 114 | + break; | |
| 115 | + case 'c': | |
| 116 | + system = EARGF(usage()); | |
| 117 | + break; | |
| 118 | +/* | |
| 119 | + case 'c': | |
| 120 | + cflag++; | |
| 121 | + cmd[0] = '!'; | |
| 122 | + cmd[1] = '\0'; | |
| 123 | + while(p = ARGF()) { | |
| 124 | + strcat(cmd, " "); | |
| 125 | + strcat(cmd, p); | |
| 126 | + } | |
| 127 | + break; | |
| 128 | +*/ | |
| 129 | + case 'u': | |
| 130 | + user = EARGF(usage()); | |
| 131 | + break; | |
| 132 | + case 's': | |
| 133 | + secstoreserver = EARGF(usage()); | |
| 134 | + break; | |
| 135 | + default: | |
| 136 | + usage(); | |
| 137 | + }ARGEND; | |
| 138 | + | |
| 139 | + if(secstoreserver == nil) | |
| 140 | + secstoreserver = authserver; | |
| 141 | + | |
| 142 | + if(secstoreserver && havesecstore(secstoreserver, user)){ | |
| 143 | + s = secstorefetch(secstoreserver, user, nil); | |
| 144 | + if(s){ | |
| 145 | + if(strlen(s) >= sizeof secstorebuf) | |
| 146 | + panic("secstore data too big"); | |
| 147 | + strcpy(secstorebuf, s); | |
| 148 | + } | |
| 149 | + } | |
| 150 | + | |
| 151 | + | |
| 152 | + if(argc != 0) | |
| 153 | + usage(); | |
| 154 | + | |
| 155 | + if(system == nil) { | |
| 156 | + p = getenv("cpu"); | |
| 157 | + if(p == 0) | |
| 158 | + fatal(0, "set $cpu"); | |
| 159 | + system = p; | |
| 160 | + } | |
| 161 | + | |
| 162 | + if(err = rexcall(&data, system, srvname)) | |
| 163 | + fatal(1, "%s: %s", err, system); | |
| 164 | + | |
| 165 | + /* Tell the remote side the command to execute and where our working directory is */ | |
| 166 | + if(cflag) | |
| 167 | + writestr(data, cmd, "command", 0); | |
| 168 | + if(getcwd(dat, sizeof(dat)) == 0) | |
| 169 | + writestr(data, "NO", "dir", 0); | |
| 170 | + else | |
| 171 | + writestr(data, dat, "dir", 0); | |
| 172 | + | |
| 173 | + /* | |
| 174 | + * Wait for the other end to execute and start our file service | |
| 175 | + * of /mnt/term | |
| 176 | + */ | |
| 177 | + if(readstr(data, buf, sizeof(buf)) < 0) | |
| 178 | + fatal(1, "waiting for FS: %r"); | |
| 179 | + if(strncmp("FS", buf, 2) != 0) { | |
| 180 | + print("remote cpu: %s", buf); | |
| 181 | + exits(buf); | |
| 182 | + } | |
| 183 | + | |
| 184 | + if(readstr(data, buf, sizeof buf) < 0) | |
| 185 | + fatal(1, "waiting for remote export: %r"); | |
| 186 | + if(strcmp(buf, "/") != 0){ | |
| 187 | + print("remote cpu: %s" , buf); | |
| 188 | + exits(buf); | |
| 189 | + } | |
| 190 | + write(data, "OK", 2); | |
| 191 | + | |
| 192 | + /* Begin serving the gnot namespace */ | |
| 193 | + exportfs(data, msgsize); | |
| 194 | + fatal(1, "starting exportfs"); | |
| 195 | +} | |
| 196 | + | |
| 197 | +void | |
| 198 | +fatal(int syserr, char *fmt, ...) | |
| 199 | +{ | |
| 200 | + Fmt f; | |
| 201 | + char *str; | |
| 202 | + va_list arg; | |
| 203 | + | |
| 204 | + fmtstrinit(&f); | |
| 205 | + fmtprint(&f, "cpu: "); | |
| 206 | + va_start(arg, fmt); | |
| 207 | + fmtvprint(&f, fmt, arg); | |
| 208 | + va_end(arg); | |
| 209 | + if(syserr) | |
| 210 | + fmtprint(&f, ": %r"); | |
| 211 | + fmtprint(&f, "\n"); | |
| 212 | + str = fmtstrflush(&f); | |
| 213 | + write(2, str, strlen(str)); | |
| 214 | + exits(str); | |
| 215 | +} | |
| 216 | + | |
| 217 | +char *negstr = "negotiating authentication method"; | |
| 218 | + | |
| 219 | +char bug[256]; | |
| 220 | + | |
| 221 | +char* | |
| 222 | +rexcall(int *fd, char *host, char *service) | |
| 223 | +{ | |
| 224 | + char *na; | |
| 225 | + char dir[MaxStr]; | |
| 226 | + char err[ERRMAX]; | |
| 227 | + char msg[MaxStr]; | |
| 228 | + int n; | |
| 229 | + | |
| 230 | + na = netmkaddr(host, "tcp", "17010"); | |
| 231 | + if((*fd = dial(na, 0, dir, 0)) < 0) | |
| 232 | + return "can't dial"; | |
| 233 | + | |
| 234 | + /* negotiate authentication mechanism */ | |
| 235 | + if(ealgs != nil) | |
| 236 | + snprint(msg, sizeof(msg), "%s %s", am->name, ealgs); | |
| 237 | + else | |
| 238 | + snprint(msg, sizeof(msg), "%s", am->name); | |
| 239 | + writestr(*fd, msg, negstr, 0); | |
| 240 | + n = readstr(*fd, err, sizeof err); | |
| 241 | + if(n < 0) | |
| 242 | + return negstr; | |
| 243 | + if(*err){ | |
| 244 | + werrstr(err); | |
| 245 | + return negstr; | |
| 246 | + } | |
| 247 | + | |
| 248 | + /* authenticate */ | |
| 249 | + *fd = (*am->cf)(*fd); | |
| 250 | + if(*fd < 0) | |
| 251 | + return "can't authenticate"; | |
| 252 | + return 0; | |
| 253 | +} | |
| 254 | + | |
| 255 | +void | |
| 256 | +writestr(int fd, char *str, char *thing, int ignore) | |
| 257 | +{ | |
| 258 | + int l, n; | |
| 259 | + | |
| 260 | + l = strlen(str); | |
| 261 | + n = write(fd, str, l+1); | |
| 262 | + if(!ignore && n < 0) | |
| 263 | + fatal(1, "writing network: %s", thing); | |
| 264 | +} | |
| 265 | + | |
| 266 | +int | |
| 267 | +readstr(int fd, char *str, int len) | |
| 268 | +{ | |
| 269 | + int n; | |
| 270 | + | |
| 271 | + while(len) { | |
| 272 | + n = read(fd, str, 1); | |
| 273 | + if(n < 0) | |
| 274 | + return -1; | |
| 275 | + if(*str == '\0') | |
| 276 | + return 0; | |
| 277 | + str++; | |
| 278 | + len--; | |
| 279 | + } | |
| 280 | + return -1; | |
| 281 | +} | |
| 282 | + | |
| 283 | +static int | |
| 284 | +readln(char *buf, int n) | |
| 285 | +{ | |
| 286 | + int i; | |
| 287 | + char *p; | |
| 288 | + | |
| 289 | + n--; /* room for \0 */ | |
| 290 | + p = buf; | |
| 291 | + for(i=0; i<n; i++){ | |
| 292 | + if(read(0, p, 1) != 1) | |
| 293 | + break; | |
| 294 | + if(*p == '\n' || *p == '\r') | |
| 295 | + break; | |
| 296 | + p++; | |
| 297 | + } | |
| 298 | + *p = '\0'; | |
| 299 | + return p-buf; | |
| 300 | +} | |
| 301 | + | |
| 302 | +/* | |
| 303 | + * user level challenge/response | |
| 304 | + */ | |
| 305 | +static int | |
| 306 | +netkeyauth(int fd) | |
| 307 | +{ | |
| 308 | + char chall[32]; | |
| 309 | + char resp[32]; | |
| 310 | + | |
| 311 | + strecpy(chall, chall+sizeof chall, getuser()); | |
| 312 | + print("user[%s]: ", chall); | |
| 313 | + if(readln(resp, sizeof(resp)) < 0) | |
| 314 | + return -1; | |
| 315 | + if(*resp != 0) | |
| 316 | + strcpy(chall, resp); | |
| 317 | + writestr(fd, chall, "challenge/response", 1); | |
| 318 | + | |
| 319 | + for(;;){ | |
| 320 | + if(readstr(fd, chall, sizeof chall) < 0) | |
| 321 | + break; | |
| 322 | + if(*chall == 0) | |
| 323 | + return fd; | |
| 324 | + print("challenge: %s\nresponse: ", chall); | |
| 325 | + if(readln(resp, sizeof(resp)) < 0) | |
| 326 | + break; | |
| 327 | + writestr(fd, resp, "challenge/response", 1); | |
| 328 | + } | |
| 329 | + return -1; | |
| 330 | +} | |
| 331 | + | |
| 332 | +static int | |
| 333 | +netkeysrvauth(int fd, char *user) | |
| 334 | +{ | |
| 335 | + return -1; | |
| 336 | +} | |
| 337 | + | |
| 338 | +static void | |
| 339 | +mksecret(char *t, uchar *f) | |
| 340 | +{ | |
| 341 | + sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux", | |
| 342 | + f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]); | |
| 343 | +} | |
| 344 | + | |
| 345 | +/* | |
| 346 | + * plan9 authentication followed by rc4 encryption | |
| 347 | + */ | |
| 348 | +static int | |
| 349 | +p9auth(int fd) | |
| 350 | +{ | |
| 351 | + uchar key[16]; | |
| 352 | + uchar digest[SHA1dlen]; | |
| 353 | + char fromclientsecret[21]; | |
| 354 | + char fromserversecret[21]; | |
| 355 | + int i; | |
| 356 | + AuthInfo *ai; | |
| 357 | + | |
| 358 | + ai = p9any(fd); | |
| 359 | + if(ai == nil) | |
| 360 | + return -1; | |
| 361 | + memmove(key+4, ai->secret, ai->nsecret); | |
| 362 | + if(ealgs == nil) | |
| 363 | + return fd; | |
| 364 | + | |
| 365 | + /* exchange random numbers */ | |
| 366 | + srand(truerand()); | |
| 367 | + for(i = 0; i < 4; i++) | |
| 368 | + key[i] = rand(); | |
| 369 | + if(write(fd, key, 4) != 4) | |
| 370 | + return -1; | |
| 371 | + if(readn(fd, key+12, 4) != 4) | |
| 372 | + return -1; | |
| 373 | + | |
| 374 | + /* scramble into two secrets */ | |
| 375 | + sha1(key, sizeof(key), digest, nil); | |
| 376 | + mksecret(fromclientsecret, digest); | |
| 377 | + mksecret(fromserversecret, digest+10); | |
| 378 | + | |
| 379 | + /* set up encryption */ | |
| 380 | + i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil); | |
| 381 | + if(i < 0) | |
| 382 | + werrstr("can't establish ssl connection: %r"); | |
| 383 | + return i; | |
| 384 | +} | |
| 385 | + | |
| 386 | +int | |
| 387 | +authdial(char *net, char *dom) | |
| 388 | +{ | |
| 389 | + int fd; | |
| 390 | + fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0); | |
| 391 | + //print("authdial %d\n", fd); | |
| 392 | + return fd; | |
| 393 | +} | |
| 394 | + | |
| 395 | +static int | |
| 396 | +getastickets(Ticketreq *tr, char *trbuf, char *tbuf) | |
| 397 | +{ | |
| 398 | + int asfd, rv; | |
| 399 | + char *dom; | |
| 400 | + | |
| 401 | + dom = tr->authdom; | |
| 402 | + asfd = authdial(nil, dom); | |
| 403 | + if(asfd < 0) | |
| 404 | + return -1; | |
| 405 | + rv = _asgetticket(asfd, trbuf, tbuf); | |
| 406 | + close(asfd); | |
| 407 | + return rv; | |
| 408 | +} | |
| 409 | + | |
| 410 | +static int | |
| 411 | +mkserverticket(Ticketreq *tr, char *authkey, char *tbuf) | |
| 412 | +{ | |
| 413 | + int i; | |
| 414 | + Ticket t; | |
| 415 | + | |
| 416 | + if(strcmp(tr->authid, tr->hostid) != 0) | |
| 417 | + return -1; | |
| 418 | + memset(&t, 0, sizeof(t)); | |
| 419 | + memmove(t.chal, tr->chal, CHALLEN); | |
| 420 | + strcpy(t.cuid, tr->uid); | |
| 421 | + strcpy(t.suid, tr->uid); | |
| 422 | + for(i=0; i<DESKEYLEN; i++) | |
| 423 | + t.key[i] = fastrand(); | |
| 424 | + t.num = AuthTc; | |
| 425 | + convT2M(&t, tbuf, authkey); | |
| 426 | + t.num = AuthTs; | |
| 427 | + convT2M(&t, tbuf+TICKETLEN, authkey); | |
| 428 | + return 0; | |
| 429 | +} | |
| 430 | + | |
| 431 | +static int | |
| 432 | +gettickets(Ticketreq *tr, char *key, char *trbuf, char *tbuf) | |
| 433 | +{ | |
| 434 | + if(getastickets(tr, trbuf, tbuf) >= 0) | |
| 435 | + return 0; | |
| 436 | + return mkserverticket(tr, key, tbuf); | |
| 437 | +} | |
| 438 | + | |
| 439 | +AuthInfo* | |
| 440 | +p9any(int fd) | |
| 441 | +{ | |
| 442 | + char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u; | |
| 443 | + char *pass; | |
| 444 | + char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN]; | |
| 445 | + char authkey[DESKEYLEN]; | |
| 446 | + Authenticator auth; | |
| 447 | + int i, v2, n; | |
| 448 | + Ticketreq tr; | |
| 449 | + Ticket t; | |
| 450 | + AuthInfo *ai; | |
| 451 | + | |
| 452 | + if((n = readstr(fd, buf, sizeof buf)) < 0) | |
| 453 | + fatal(1, "cannot read p9any negotiation"); | |
| 454 | + bbuf = buf; | |
| 455 | + v2 = 0; | |
| 456 | + if(strncmp(buf, "v.2 ", 4) == 0){ | |
| 457 | + v2 = 1; | |
| 458 | + bbuf += 4; | |
| 459 | + } | |
| 460 | + if(p = strchr(bbuf, ' ')) | |
| 461 | + *p = 0; | |
| 462 | + p = bbuf; | |
| 463 | + if((dom = strchr(p, '@')) == nil) | |
| 464 | + fatal(1, "bad p9any domain"); | |
| 465 | + *dom++ = 0; | |
| 466 | + if(strcmp(p, "p9sk1") != 0) | |
| 467 | + fatal(1, "server did not offer p9sk1"); | |
| 468 | + | |
| 469 | + sprint(buf2, "%s %s", p, dom); | |
| 470 | + if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1) | |
| 471 | + fatal(1, "cannot write user/domain choice in p9any"); | |
| 472 | + if(v2){ | |
| 473 | + if((n = readstr(fd, buf, sizeof buf)) != 3) | |
| 474 | + fatal(1, "cannot read OK in p9any"); | |
| 475 | + if(memcmp(buf, "OK\0", 3) != 0) | |
| 476 | + fatal(1, "did not get OK in p9any"); | |
| 477 | + } | |
| 478 | + for(i=0; i<CHALLEN; i++) | |
| 479 | + cchal[i] = fastrand(); | |
| 480 | + if(write(fd, cchal, 8) != 8) | |
| 481 | + fatal(1, "cannot write p9sk1 challenge"); | |
| 482 | + | |
| 483 | + if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN) | |
| 484 | + fatal(1, "cannot read ticket request in p9sk1"); | |
| 485 | + | |
| 486 | + | |
| 487 | + convM2TR(trbuf, &tr); | |
| 488 | + u = user; | |
| 489 | + pass = findkey(&u, tr.authdom); | |
| 490 | + if(pass == nil) | |
| 491 | + again: | |
| 492 | + pass = getkey(u, tr.authdom); | |
| 493 | + if(pass == nil) | |
| 494 | + fatal(1, "no password"); | |
| 495 | + | |
| 496 | + passtokey(authkey, pass); | |
| 497 | + memset(pass, 0, strlen(pass)); | |
| 498 | + | |
| 499 | + tr.type = AuthTreq; | |
| 500 | + strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u); | |
| 501 | + strecpy(tr.uid, tr.uid+sizeof tr.uid, u); | |
| 502 | + convTR2M(&tr, trbuf); | |
| 503 | + | |
| 504 | + if(gettickets(&tr, authkey, trbuf, tbuf) < 0) | |
| 505 | + fatal(1, "cannot get auth tickets in p9sk1"); | |
| 506 | + | |
| 507 | + convM2T(tbuf, &t, authkey); | |
| 508 | + if(t.num != AuthTc){ | |
| 509 | + print("?password mismatch with auth server\n"); | |
| 510 | + goto again; | |
| 511 | + } | |
| 512 | + memmove(tbuf, tbuf+TICKETLEN, TICKETLEN); | |
| 513 | + | |
| 514 | + auth.num = AuthAc; | |
| 515 | + memmove(auth.chal, tr.chal, CHALLEN); | |
| 516 | + auth.id = 0; | |
| 517 | + convA2M(&auth, tbuf+TICKETLEN, t.key); | |
| 518 | + | |
| 519 | + if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN) | |
| 520 | + fatal(1, "cannot send ticket and authenticator back in p9sk1"); | |
| 521 | + | |
| 522 | + if(readn(fd, tbuf, AUTHENTLEN) != AUTHENTLEN) | |
| 523 | + fatal(1, "cannot read authenticator in p9sk1"); | |
| 524 | + | |
| 525 | + convM2A(tbuf, &auth, t.key); | |
| 526 | + if(auth.num != AuthAs | |
| 527 | + || memcmp(auth.chal, cchal, CHALLEN) != 0 | |
| 528 | + || auth.id != 0){ | |
| 529 | + print("?you and auth server agree about password.\n"); | |
| 530 | + print("?server is confused.\n"); | |
| 531 | + fatal(1, "server lies got %llux.%d want %llux.%d", *(vlong*)auth.chal, auth.id, *(vlong*)cchal, 0); | |
| 532 | + } | |
| 533 | + //print("i am %s there.\n", t.suid); | |
| 534 | + ai = mallocz(sizeof(AuthInfo), 1); | |
| 535 | + ai->secret = mallocz(8, 1); | |
| 536 | + des56to64((uchar*)t.key, ai->secret); | |
| 537 | + ai->nsecret = 8; | |
| 538 | + ai->suid = strdup(t.suid); | |
| 539 | + ai->cuid = strdup(t.cuid); | |
| 540 | + memset(authkey, 0, sizeof authkey); | |
| 541 | + return ai; | |
| 542 | +} | |
| 543 | + | |
| 544 | +static int | |
| 545 | +noauth(int fd) | |
| 546 | +{ | |
| 547 | + ealgs = nil; | |
| 548 | + return fd; | |
| 549 | +} | |
| 550 | + | |
| 551 | +static int | |
| 552 | +srvnoauth(int fd, char *user) | |
| 553 | +{ | |
| 554 | + strecpy(user, user+MaxStr, getuser()); | |
| 555 | + ealgs = nil; | |
| 556 | + return fd; | |
| 557 | +} | |
| 558 | + | |
| 559 | +void | |
| 560 | +loghex(uchar *p, int n) | |
| 561 | +{ | |
| 562 | + char buf[100]; | |
| 563 | + int i; | |
| 564 | + | |
| 565 | + for(i = 0; i < n; i++) | |
| 566 | + sprint(buf+2*i, "%2.2ux", p[i]); | |
| 567 | +// syslog(0, "cpu", buf); | |
| 568 | +} | |
| 569 | + | |
| 570 | +static int | |
| 571 | +srvp9auth(int fd, char *user) | |
| 572 | +{ | |
| 573 | + return -1; | |
| 574 | +} | |
| 575 | + | |
| 576 | +/* | |
| 577 | + * set authentication mechanism | |
| 578 | + */ | |
| 579 | +int | |
| 580 | +setam(char *name) | |
| 581 | +{ | |
| 582 | + for(am = authmethod; am->name != nil; am++) | |
| 583 | + if(strcmp(am->name, name) == 0) | |
| 584 | + return 0; | |
| 585 | + am = authmethod; | |
| 586 | + return -1; | |
| 587 | +} | |
| 588 | + | |
| 589 | +/* | |
| 590 | + * set authentication mechanism and encryption/hash algs | |
| 591 | + */ | |
| 592 | +int | |
| 593 | +setamalg(char *s) | |
| 594 | +{ | |
| 595 | + ealgs = strchr(s, ' '); | |
| 596 | + if(ealgs != nil) | |
| 597 | + *ealgs++ = 0; | |
| 598 | + return setam(s); | |
| 599 | +} | |
| 600 | + | |
| 601 | +char* | |
| 602 | +getuser(void) | |
| 603 | +{ | |
| 604 | + return getenv("USER"); | |
| 605 | +} | |
| 606 | + | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +extern int havesecstore(char *addr, char *owner); | |
| 2 | +extern char *secstore; | |
| 3 | +extern char secstorebuf[65536]; | |
| 4 | +extern char *secstorefetch(char *addr, char *owner, char *passwd); | |
| 5 | +extern char *authaddr; | |
| 6 | +extern char *readcons(char *prompt, char *def, int secret); | |
| 7 | +extern int exportfs(int, int); | |
| 8 | +extern char *user; | |
| 9 | +extern char *getkey(char*, char*); | |
| 10 | +extern char *findkey(char**, char*); | |
Binary file not shown.
| @@ -0,0 +1,72 @@ | ||
| 1 | +//Microsoft Developer Studio generated resource script. | |
| 2 | +// | |
| 3 | +#include "resource.h" | |
| 4 | + | |
| 5 | +#define APSTUDIO_READONLY_SYMBOLS | |
| 6 | +///////////////////////////////////////////////////////////////////////////// | |
| 7 | +// | |
| 8 | +// Generated from the TEXTINCLUDE 2 resource. | |
| 9 | +// | |
| 10 | +#include "afxres.h" | |
| 11 | + | |
| 12 | +///////////////////////////////////////////////////////////////////////////// | |
| 13 | +#undef APSTUDIO_READONLY_SYMBOLS | |
| 14 | + | |
| 15 | +///////////////////////////////////////////////////////////////////////////// | |
| 16 | +// English (U.S.) resources | |
| 17 | + | |
| 18 | +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) | |
| 19 | +#ifdef _WIN32 | |
| 20 | +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US | |
| 21 | +#pragma code_page(1252) | |
| 22 | +#endif //_WIN32 | |
| 23 | + | |
| 24 | +///////////////////////////////////////////////////////////////////////////// | |
| 25 | +// | |
| 26 | +// Icon | |
| 27 | +// | |
| 28 | + | |
| 29 | +// Icon with lowest ID value placed first to ensure application icon | |
| 30 | +// remains consistent on all systems. | |
| 31 | +IDI_ICON1 ICON DISCARDABLE "drawterm.ico" | |
| 32 | + | |
| 33 | +#ifdef APSTUDIO_INVOKED | |
| 34 | +///////////////////////////////////////////////////////////////////////////// | |
| 35 | +// | |
| 36 | +// TEXTINCLUDE | |
| 37 | +// | |
| 38 | + | |
| 39 | +1 TEXTINCLUDE DISCARDABLE | |
| 40 | +BEGIN | |
| 41 | + "resource.h\0" | |
| 42 | +END | |
| 43 | + | |
| 44 | +2 TEXTINCLUDE DISCARDABLE | |
| 45 | +BEGIN | |
| 46 | + "#include ""afxres.h""\r\n" | |
| 47 | + "\0" | |
| 48 | +END | |
| 49 | + | |
| 50 | +3 TEXTINCLUDE DISCARDABLE | |
| 51 | +BEGIN | |
| 52 | + "\r\n" | |
| 53 | + "\0" | |
| 54 | +END | |
| 55 | + | |
| 56 | +#endif // APSTUDIO_INVOKED | |
| 57 | + | |
| 58 | +#endif // English (U.S.) resources | |
| 59 | +///////////////////////////////////////////////////////////////////////////// | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | +#ifndef APSTUDIO_INVOKED | |
| 64 | +///////////////////////////////////////////////////////////////////////////// | |
| 65 | +// | |
| 66 | +// Generated from the TEXTINCLUDE 3 resource. | |
| 67 | +// | |
| 68 | + | |
| 69 | + | |
| 70 | +///////////////////////////////////////////////////////////////////////////// | |
| 71 | +#endif // not APSTUDIO_INVOKED | |
| 72 | + | |
Binary file not shown.
| @@ -0,0 +1,16 @@ | ||
| 1 | +LIB=libexportfs.a | |
| 2 | +CC=gcc | |
| 3 | +CFLAGS=-I../include -I. -I.. -c -ggdb -D_THREAD_SAFE -pthread | |
| 4 | +O=o | |
| 5 | + | |
| 6 | +OFILES=\ | |
| 7 | + exportfs.$O\ | |
| 8 | + exportsrv.$O | |
| 9 | + | |
| 10 | +$(LIB): $(OFILES) | |
| 11 | + ar r $(LIB) $(OFILES) | |
| 12 | + ranlib $(LIB) | |
| 13 | + | |
| 14 | +%.$O: %.c | |
| 15 | + $(CC) $(CFLAGS) $*.c | |
| 16 | + | |
| @@ -0,0 +1,503 @@ | ||
| 1 | +/* | |
| 2 | + * exportfs - Export a plan 9 name space across a network | |
| 3 | + */ | |
| 4 | +#include <u.h> | |
| 5 | +#include <libc.h> | |
| 6 | +#include <fcall.h> | |
| 7 | +#include <libsec.h> | |
| 8 | +#include "drawterm.h" | |
| 9 | +#define Extern | |
| 10 | +#include "exportfs.h" | |
| 11 | + | |
| 12 | +/* #define QIDPATH ((1LL<<48)-1) */ | |
| 13 | +#define QIDPATH ((((vlong)1)<<48)-1) | |
| 14 | +vlong newqid = 0; | |
| 15 | + | |
| 16 | +void (*fcalls[256])(Fsrpc*); | |
| 17 | + | |
| 18 | +/* accounting and debugging counters */ | |
| 19 | +int filecnt; | |
| 20 | +int freecnt; | |
| 21 | +int qidcnt; | |
| 22 | +int qfreecnt; | |
| 23 | +int ncollision; | |
| 24 | +int netfd; | |
| 25 | + | |
| 26 | +int | |
| 27 | +exportfs(int fd, int msgsz) | |
| 28 | +{ | |
| 29 | + char buf[ERRMAX], ebuf[ERRMAX]; | |
| 30 | + Fsrpc *r; | |
| 31 | + int n; | |
| 32 | + char *dbfile, *srv, *file; | |
| 33 | + ulong initial; | |
| 34 | + | |
| 35 | + fcalls[Tversion] = Xversion; | |
| 36 | + fcalls[Tauth] = Xauth; | |
| 37 | + fcalls[Tflush] = Xflush; | |
| 38 | + fcalls[Tattach] = Xattach; | |
| 39 | + fcalls[Twalk] = Xwalk; | |
| 40 | + fcalls[Topen] = slave; | |
| 41 | + fcalls[Tcreate] = Xcreate; | |
| 42 | + fcalls[Tclunk] = Xclunk; | |
| 43 | + fcalls[Tread] = slave; | |
| 44 | + fcalls[Twrite] = slave; | |
| 45 | + fcalls[Tremove] = Xremove; | |
| 46 | + fcalls[Tstat] = Xstat; | |
| 47 | + fcalls[Twstat] = Xwstat; | |
| 48 | + | |
| 49 | + srvfd = -1; | |
| 50 | + netfd = fd; | |
| 51 | + //dbg = 1; | |
| 52 | + | |
| 53 | + strcpy(buf, "this is buf"); | |
| 54 | + strcpy(ebuf, "this is ebuf"); | |
| 55 | + DEBUG(DFD, "exportfs: started\n"); | |
| 56 | + | |
| 57 | +// rfork(RFNOTEG); | |
| 58 | + | |
| 59 | + messagesize = msgsz; | |
| 60 | + if(messagesize == 0){ | |
| 61 | + messagesize = iounit(netfd); | |
| 62 | + if(messagesize == 0) | |
| 63 | + messagesize = 8192+IOHDRSZ; | |
| 64 | + } | |
| 65 | + | |
| 66 | + Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); | |
| 67 | +// for(i=0; i<Nr_workbufs; i++) | |
| 68 | +// Workq[i].buf = emallocz(messagesize); | |
| 69 | + fhash = emallocz(sizeof(Fid*)*FHASHSIZE); | |
| 70 | + | |
| 71 | + fmtinstall('F', fcallfmt); | |
| 72 | + | |
| 73 | + initroot(); | |
| 74 | + | |
| 75 | + DEBUG(DFD, "exportfs: %s\n", buf); | |
| 76 | + | |
| 77 | + /* | |
| 78 | + * Start serving file requests from the network | |
| 79 | + */ | |
| 80 | + for(;;) { | |
| 81 | + r = getsbuf(); | |
| 82 | + if(r == 0) | |
| 83 | + fatal("Out of service buffers"); | |
| 84 | + | |
| 85 | + DEBUG(DFD, "read9p..."); | |
| 86 | + n = read9pmsg(netfd, r->buf, messagesize); | |
| 87 | + if(n <= 0) | |
| 88 | + fatal(nil); | |
| 89 | + | |
| 90 | + if(convM2S(r->buf, n, &r->work) == 0) | |
| 91 | + fatal("convM2S format error"); | |
| 92 | + | |
| 93 | + DEBUG(DFD, "%F\n", &r->work); | |
| 94 | + (fcalls[r->work.type])(r); | |
| 95 | + } | |
| 96 | +} | |
| 97 | + | |
| 98 | +void | |
| 99 | +reply(Fcall *r, Fcall *t, char *err) | |
| 100 | +{ | |
| 101 | + uchar *data; | |
| 102 | + int m, n; | |
| 103 | + | |
| 104 | + t->tag = r->tag; | |
| 105 | + t->fid = r->fid; | |
| 106 | + if(err) { | |
| 107 | + t->type = Rerror; | |
| 108 | + t->ename = err; | |
| 109 | + } | |
| 110 | + else | |
| 111 | + t->type = r->type + 1; | |
| 112 | + | |
| 113 | + DEBUG(DFD, "\t%F\n", t); | |
| 114 | + | |
| 115 | + data = malloc(messagesize); /* not mallocz; no need to clear */ | |
| 116 | + if(data == nil) | |
| 117 | + fatal(Enomem); | |
| 118 | + n = convS2M(t, data, messagesize); | |
| 119 | + if((m=write(netfd, data, n))!=n){ | |
| 120 | + fprint(2, "wrote %d got %d (%r)\n", n, m); | |
| 121 | + fatal("write"); | |
| 122 | + } | |
| 123 | + free(data); | |
| 124 | +} | |
| 125 | + | |
| 126 | +Fid * | |
| 127 | +getfid(int nr) | |
| 128 | +{ | |
| 129 | + Fid *f; | |
| 130 | + | |
| 131 | + for(f = fidhash(nr); f; f = f->next) | |
| 132 | + if(f->nr == nr) | |
| 133 | + return f; | |
| 134 | + | |
| 135 | + return 0; | |
| 136 | +} | |
| 137 | + | |
| 138 | +int | |
| 139 | +freefid(int nr) | |
| 140 | +{ | |
| 141 | + Fid *f, **l; | |
| 142 | + char buf[128]; | |
| 143 | + | |
| 144 | + l = &fidhash(nr); | |
| 145 | + for(f = *l; f; f = f->next) { | |
| 146 | + if(f->nr == nr) { | |
| 147 | + if(f->mid) { | |
| 148 | + sprint(buf, "/mnt/exportfs/%d", f->mid); | |
| 149 | + unmount(0, buf); | |
| 150 | + psmap[f->mid] = 0; | |
| 151 | + } | |
| 152 | + if(f->f) { | |
| 153 | + freefile(f->f); | |
| 154 | + f->f = nil; | |
| 155 | + } | |
| 156 | + *l = f->next; | |
| 157 | + f->next = fidfree; | |
| 158 | + fidfree = f; | |
| 159 | + return 1; | |
| 160 | + } | |
| 161 | + l = &f->next; | |
| 162 | + } | |
| 163 | + | |
| 164 | + return 0; | |
| 165 | +} | |
| 166 | + | |
| 167 | +Fid * | |
| 168 | +newfid(int nr) | |
| 169 | +{ | |
| 170 | + Fid *new, **l; | |
| 171 | + int i; | |
| 172 | + | |
| 173 | + l = &fidhash(nr); | |
| 174 | + for(new = *l; new; new = new->next) | |
| 175 | + if(new->nr == nr) | |
| 176 | + return 0; | |
| 177 | + | |
| 178 | + if(fidfree == 0) { | |
| 179 | + fidfree = emallocz(sizeof(Fid) * Fidchunk); | |
| 180 | + | |
| 181 | + for(i = 0; i < Fidchunk-1; i++) | |
| 182 | + fidfree[i].next = &fidfree[i+1]; | |
| 183 | + | |
| 184 | + fidfree[Fidchunk-1].next = 0; | |
| 185 | + } | |
| 186 | + | |
| 187 | + new = fidfree; | |
| 188 | + fidfree = new->next; | |
| 189 | + | |
| 190 | + memset(new, 0, sizeof(Fid)); | |
| 191 | + new->next = *l; | |
| 192 | + *l = new; | |
| 193 | + new->nr = nr; | |
| 194 | + new->fid = -1; | |
| 195 | + new->mid = 0; | |
| 196 | + | |
| 197 | + return new; | |
| 198 | +} | |
| 199 | + | |
| 200 | +Fsrpc * | |
| 201 | +getsbuf(void) | |
| 202 | +{ | |
| 203 | + static int ap; | |
| 204 | + int look, rounds; | |
| 205 | + Fsrpc *wb; | |
| 206 | + int small_instead_of_fast = 1; | |
| 207 | + | |
| 208 | + if(small_instead_of_fast) | |
| 209 | + ap = 0; /* so we always start looking at the beginning and reuse buffers */ | |
| 210 | + | |
| 211 | + for(rounds = 0; rounds < 10; rounds++) { | |
| 212 | + for(look = 0; look < Nr_workbufs; look++) { | |
| 213 | + if(++ap == Nr_workbufs) | |
| 214 | + ap = 0; | |
| 215 | + if(Workq[ap].busy == 0) | |
| 216 | + break; | |
| 217 | + } | |
| 218 | + | |
| 219 | + if(look == Nr_workbufs){ | |
| 220 | + sleep(10 * rounds); | |
| 221 | + continue; | |
| 222 | + } | |
| 223 | + | |
| 224 | + wb = &Workq[ap]; | |
| 225 | + wb->pid = 0; | |
| 226 | + wb->canint = 0; | |
| 227 | + wb->flushtag = NOTAG; | |
| 228 | + wb->busy = 1; | |
| 229 | + if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ | |
| 230 | + wb->buf = emallocz(messagesize); | |
| 231 | + return wb; | |
| 232 | + } | |
| 233 | + fatal("No more work buffers"); | |
| 234 | + return nil; | |
| 235 | +} | |
| 236 | + | |
| 237 | +void | |
| 238 | +freefile(File *f) | |
| 239 | +{ | |
| 240 | + File *parent, *child; | |
| 241 | + | |
| 242 | +Loop: | |
| 243 | + f->ref--; | |
| 244 | + if(f->ref > 0) | |
| 245 | + return; | |
| 246 | + freecnt++; | |
| 247 | + if(f->ref < 0) abort(); | |
| 248 | + DEBUG(DFD, "free %s\n", f->name); | |
| 249 | + /* delete from parent */ | |
| 250 | + parent = f->parent; | |
| 251 | + if(parent->child == f) | |
| 252 | + parent->child = f->childlist; | |
| 253 | + else{ | |
| 254 | + for(child=parent->child; child->childlist!=f; child=child->childlist) | |
| 255 | + if(child->childlist == nil) | |
| 256 | + fatal("bad child list"); | |
| 257 | + child->childlist = f->childlist; | |
| 258 | + } | |
| 259 | + freeqid(f->qidt); | |
| 260 | + free(f->name); | |
| 261 | + f->name = nil; | |
| 262 | + free(f); | |
| 263 | + f = parent; | |
| 264 | + if(f != nil) | |
| 265 | + goto Loop; | |
| 266 | +} | |
| 267 | + | |
| 268 | +File * | |
| 269 | +file(File *parent, char *name) | |
| 270 | +{ | |
| 271 | + Dir *dir; | |
| 272 | + char *path; | |
| 273 | + File *f; | |
| 274 | + | |
| 275 | + DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name); | |
| 276 | + | |
| 277 | + path = makepath(parent, name); | |
| 278 | + dir = dirstat(path); | |
| 279 | + free(path); | |
| 280 | + if(dir == nil) | |
| 281 | + return nil; | |
| 282 | + | |
| 283 | + for(f = parent->child; f; f = f->childlist) | |
| 284 | + if(strcmp(name, f->name) == 0) | |
| 285 | + break; | |
| 286 | + | |
| 287 | + if(f == nil){ | |
| 288 | + f = emallocz(sizeof(File)); | |
| 289 | + f->name = estrdup(name); | |
| 290 | + | |
| 291 | + f->parent = parent; | |
| 292 | + f->childlist = parent->child; | |
| 293 | + parent->child = f; | |
| 294 | + parent->ref++; | |
| 295 | + f->ref = 0; | |
| 296 | + filecnt++; | |
| 297 | + } | |
| 298 | + f->ref++; | |
| 299 | + f->qid.type = dir->qid.type; | |
| 300 | + f->qid.vers = dir->qid.vers; | |
| 301 | + f->qidt = uniqueqid(dir); | |
| 302 | + f->qid.path = f->qidt->uniqpath; | |
| 303 | + | |
| 304 | + f->inval = 0; | |
| 305 | + | |
| 306 | + free(dir); | |
| 307 | + | |
| 308 | + return f; | |
| 309 | +} | |
| 310 | + | |
| 311 | +void | |
| 312 | +initroot(void) | |
| 313 | +{ | |
| 314 | + Dir *dir; | |
| 315 | + | |
| 316 | + root = emallocz(sizeof(File)); | |
| 317 | + root->name = estrdup("."); | |
| 318 | + | |
| 319 | + dir = dirstat(root->name); | |
| 320 | + if(dir == nil) | |
| 321 | + fatal("root stat"); | |
| 322 | + | |
| 323 | + root->ref = 1; | |
| 324 | + root->qid.vers = dir->qid.vers; | |
| 325 | + root->qidt = uniqueqid(dir); | |
| 326 | + root->qid.path = root->qidt->uniqpath; | |
| 327 | + root->qid.type = QTDIR; | |
| 328 | + free(dir); | |
| 329 | + | |
| 330 | + psmpt = emallocz(sizeof(File)); | |
| 331 | + psmpt->name = estrdup("/"); | |
| 332 | + | |
| 333 | + dir = dirstat(psmpt->name); | |
| 334 | + if(dir == nil) | |
| 335 | + return; | |
| 336 | + | |
| 337 | + psmpt->ref = 1; | |
| 338 | + psmpt->qid.vers = dir->qid.vers; | |
| 339 | + psmpt->qidt = uniqueqid(dir); | |
| 340 | + psmpt->qid.path = psmpt->qidt->uniqpath; | |
| 341 | + free(dir); | |
| 342 | + | |
| 343 | + psmpt = file(psmpt, "mnt"); | |
| 344 | + if(psmpt == 0) | |
| 345 | + return; | |
| 346 | + psmpt = file(psmpt, "exportfs"); | |
| 347 | +} | |
| 348 | + | |
| 349 | +char* | |
| 350 | +makepath(File *p, char *name) | |
| 351 | +{ | |
| 352 | + int i, n; | |
| 353 | + char *c, *s, *path, *seg[256]; | |
| 354 | + | |
| 355 | + seg[0] = name; | |
| 356 | + n = strlen(name)+2; | |
| 357 | + for(i = 1; i < 256 && p; i++, p = p->parent){ | |
| 358 | + seg[i] = p->name; | |
| 359 | + n += strlen(p->name)+1; | |
| 360 | + } | |
| 361 | + path = malloc(n); | |
| 362 | + if(path == nil) | |
| 363 | + fatal("out of memory"); | |
| 364 | + s = path; | |
| 365 | + | |
| 366 | + while(i--) { | |
| 367 | + for(c = seg[i]; *c; c++) | |
| 368 | + *s++ = *c; | |
| 369 | + *s++ = '/'; | |
| 370 | + } | |
| 371 | + while(s[-1] == '/') | |
| 372 | + s--; | |
| 373 | + *s = '\0'; | |
| 374 | + | |
| 375 | + return path; | |
| 376 | +} | |
| 377 | + | |
| 378 | +int | |
| 379 | +qidhash(vlong path) | |
| 380 | +{ | |
| 381 | + int h, n; | |
| 382 | + | |
| 383 | + h = 0; | |
| 384 | + for(n=0; n<64; n+=Nqidbits){ | |
| 385 | + h ^= path; | |
| 386 | + path >>= Nqidbits; | |
| 387 | + } | |
| 388 | + return h & (Nqidtab-1); | |
| 389 | +} | |
| 390 | + | |
| 391 | +void | |
| 392 | +freeqid(Qidtab *q) | |
| 393 | +{ | |
| 394 | + ulong h; | |
| 395 | + Qidtab *l; | |
| 396 | + | |
| 397 | + q->ref--; | |
| 398 | + if(q->ref > 0) | |
| 399 | + return; | |
| 400 | + qfreecnt++; | |
| 401 | + h = qidhash(q->path); | |
| 402 | + if(qidtab[h] == q) | |
| 403 | + qidtab[h] = q->next; | |
| 404 | + else{ | |
| 405 | + for(l=qidtab[h]; l->next!=q; l=l->next) | |
| 406 | + if(l->next == nil) | |
| 407 | + fatal("bad qid list"); | |
| 408 | + l->next = q->next; | |
| 409 | + } | |
| 410 | + free(q); | |
| 411 | +} | |
| 412 | + | |
| 413 | +Qidtab* | |
| 414 | +qidlookup(Dir *d) | |
| 415 | +{ | |
| 416 | + ulong h; | |
| 417 | + Qidtab *q; | |
| 418 | + | |
| 419 | + h = qidhash(d->qid.path); | |
| 420 | + for(q=qidtab[h]; q!=nil; q=q->next) | |
| 421 | + if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path) | |
| 422 | + return q; | |
| 423 | + return nil; | |
| 424 | +} | |
| 425 | + | |
| 426 | +int | |
| 427 | +qidexists(vlong path) | |
| 428 | +{ | |
| 429 | + int h; | |
| 430 | + Qidtab *q; | |
| 431 | + | |
| 432 | + for(h=0; h<Nqidtab; h++) | |
| 433 | + for(q=qidtab[h]; q!=nil; q=q->next) | |
| 434 | + if(q->uniqpath == path) | |
| 435 | + return 1; | |
| 436 | + return 0; | |
| 437 | +} | |
| 438 | + | |
| 439 | +Qidtab* | |
| 440 | +uniqueqid(Dir *d) | |
| 441 | +{ | |
| 442 | + ulong h; | |
| 443 | + vlong path; | |
| 444 | + Qidtab *q; | |
| 445 | + | |
| 446 | + q = qidlookup(d); | |
| 447 | + if(q != nil){ | |
| 448 | + q->ref++; | |
| 449 | + return q; | |
| 450 | + } | |
| 451 | + path = d->qid.path; | |
| 452 | + while(qidexists(path)){ | |
| 453 | + DEBUG(DFD, "collision on %s\n", d->name); | |
| 454 | + /* collision: find a new one */ | |
| 455 | + ncollision++; | |
| 456 | + path &= QIDPATH; | |
| 457 | + ++newqid; | |
| 458 | + if(newqid >= (1<<16)){ | |
| 459 | + DEBUG(DFD, "collision wraparound\n"); | |
| 460 | + newqid = 1; | |
| 461 | + } | |
| 462 | + path |= newqid<<48; | |
| 463 | + DEBUG(DFD, "assign qid %.16llux\n", path); | |
| 464 | + } | |
| 465 | + q = mallocz(sizeof(Qidtab), 1); | |
| 466 | + if(q == nil) | |
| 467 | + fatal("no memory for qid table"); | |
| 468 | + qidcnt++; | |
| 469 | + q->ref = 1; | |
| 470 | + q->type = d->type; | |
| 471 | + q->dev = d->dev; | |
| 472 | + q->path = d->qid.path; | |
| 473 | + q->uniqpath = path; | |
| 474 | + h = qidhash(d->qid.path); | |
| 475 | + q->next = qidtab[h]; | |
| 476 | + qidtab[h] = q; | |
| 477 | + return q; | |
| 478 | +} | |
| 479 | + | |
| 480 | +void | |
| 481 | +fatal(char *s, ...) | |
| 482 | +{ | |
| 483 | + char buf[ERRMAX]; | |
| 484 | + va_list arg; | |
| 485 | + Proc *m; | |
| 486 | + | |
| 487 | + if (s) { | |
| 488 | + va_start(arg, s); | |
| 489 | + vsnprint(buf, ERRMAX, s, arg); | |
| 490 | + va_end(arg); | |
| 491 | + } | |
| 492 | + | |
| 493 | + /* Clear away the slave children */ | |
| 494 | +// for(m = Proclist; m; m = m->next) | |
| 495 | +// postnote(PNPROC, m->pid, "kill"); | |
| 496 | + | |
| 497 | + DEBUG(DFD, "%s\n", buf); | |
| 498 | + if (s) | |
| 499 | + sysfatal(buf); | |
| 500 | + else | |
| 501 | + exits(nil); | |
| 502 | +} | |
| 503 | + | |
| @@ -0,0 +1,148 @@ | ||
| 1 | +/* | |
| 2 | + * exportfs.h - definitions for exporting file server | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#define DEBUG if(!dbg){}else fprint | |
| 6 | +#define DFD 2 | |
| 7 | +#define fidhash(s) fhash[s%FHASHSIZE] | |
| 8 | + | |
| 9 | +#define Proc Exproc | |
| 10 | + | |
| 11 | + | |
| 12 | +typedef struct Fsrpc Fsrpc; | |
| 13 | +typedef struct Fid Fid; | |
| 14 | +typedef struct File File; | |
| 15 | +typedef struct Proc Proc; | |
| 16 | +typedef struct Qidtab Qidtab; | |
| 17 | + | |
| 18 | +struct Fsrpc | |
| 19 | +{ | |
| 20 | + int busy; /* Work buffer has pending rpc to service */ | |
| 21 | + int pid; /* Pid of slave process executing the rpc */ | |
| 22 | + int canint; /* Interrupt gate */ | |
| 23 | + int flushtag; /* Tag on which to reply to flush */ | |
| 24 | + Fcall work; /* Plan 9 incoming Fcall */ | |
| 25 | + uchar *buf; /* Data buffer */ | |
| 26 | +}; | |
| 27 | + | |
| 28 | +struct Fid | |
| 29 | +{ | |
| 30 | + int fid; /* system fd for i/o */ | |
| 31 | + File *f; /* File attached to this fid */ | |
| 32 | + int mode; | |
| 33 | + int nr; /* fid number */ | |
| 34 | + int mid; /* Mount id */ | |
| 35 | + Fid *next; /* hash link */ | |
| 36 | +}; | |
| 37 | + | |
| 38 | +struct File | |
| 39 | +{ | |
| 40 | + char *name; | |
| 41 | + int ref; | |
| 42 | + Qid qid; | |
| 43 | + Qidtab *qidt; | |
| 44 | + int inval; | |
| 45 | + File *parent; | |
| 46 | + File *child; | |
| 47 | + File *childlist; | |
| 48 | +}; | |
| 49 | + | |
| 50 | +struct Proc | |
| 51 | +{ | |
| 52 | + int pid; | |
| 53 | + int busy; | |
| 54 | + Proc *next; | |
| 55 | +}; | |
| 56 | + | |
| 57 | +struct Qidtab | |
| 58 | +{ | |
| 59 | + int ref; | |
| 60 | + int type; | |
| 61 | + int dev; | |
| 62 | + vlong path; | |
| 63 | + vlong uniqpath; | |
| 64 | + Qidtab *next; | |
| 65 | +}; | |
| 66 | + | |
| 67 | +enum | |
| 68 | +{ | |
| 69 | + MAXPROC = 50, | |
| 70 | + FHASHSIZE = 64, | |
| 71 | + Nr_workbufs = 50, | |
| 72 | + Fidchunk = 1000, | |
| 73 | + Npsmpt = 32, | |
| 74 | + Nqidbits = 5, | |
| 75 | + Nqidtab = (1<<Nqidbits), | |
| 76 | +}; | |
| 77 | + | |
| 78 | +#define Enomem Exenomem | |
| 79 | +#define Ebadfix Exebadfid | |
| 80 | +#define Enotdir Exenotdir | |
| 81 | +#define Edupfid Exedupfid | |
| 82 | +#define Eopen Exeopen | |
| 83 | +#define Exmnt Exexmnt | |
| 84 | +#define Emip Exemip | |
| 85 | +#define Enopsmt Exenopsmt | |
| 86 | + | |
| 87 | +extern char Ebadfid[]; | |
| 88 | +extern char Enotdir[]; | |
| 89 | +extern char Edupfid[]; | |
| 90 | +extern char Eopen[]; | |
| 91 | +extern char Exmnt[]; | |
| 92 | +extern char Enomem[]; | |
| 93 | +extern char Emip[]; | |
| 94 | +extern char Enopsmt[]; | |
| 95 | + | |
| 96 | +Extern Fsrpc *Workq; | |
| 97 | +Extern int dbg; | |
| 98 | +Extern File *root; | |
| 99 | +Extern File *psmpt; | |
| 100 | +Extern Fid **fhash; | |
| 101 | +Extern Fid *fidfree; | |
| 102 | +Extern Proc *Proclist; | |
| 103 | +Extern char psmap[Npsmpt]; | |
| 104 | +Extern Qidtab *qidtab[Nqidtab]; | |
| 105 | +Extern ulong messagesize; | |
| 106 | +Extern int srvfd; | |
| 107 | + | |
| 108 | +/* File system protocol service procedures */ | |
| 109 | +void Xattach(Fsrpc*); | |
| 110 | +void Xauth(Fsrpc*); | |
| 111 | +void Xclunk(Fsrpc*); | |
| 112 | +void Xcreate(Fsrpc*); | |
| 113 | +void Xflush(Fsrpc*); | |
| 114 | +void Xnop(Fsrpc*); | |
| 115 | +void Xremove(Fsrpc*); | |
| 116 | +void Xstat(Fsrpc*); | |
| 117 | +void Xversion(Fsrpc*); | |
| 118 | +void Xwalk(Fsrpc*); | |
| 119 | +void Xwstat(Fsrpc*); | |
| 120 | +void slave(Fsrpc*); | |
| 121 | + | |
| 122 | +void reply(Fcall*, Fcall*, char*); | |
| 123 | +Fid *getfid(int); | |
| 124 | +int freefid(int); | |
| 125 | +Fid *newfid(int); | |
| 126 | +Fsrpc *getsbuf(void); | |
| 127 | +void initroot(void); | |
| 128 | +void fatal(char*, ...); | |
| 129 | +char* makepath(File*, char*); | |
| 130 | +File *file(File*, char*); | |
| 131 | +void freefile(File*); | |
| 132 | +void slaveopen(Fsrpc*); | |
| 133 | +void slaveread(Fsrpc*); | |
| 134 | +void slavewrite(Fsrpc*); | |
| 135 | +void blockingslave(void*); | |
| 136 | +void reopen(Fid *f); | |
| 137 | +void noteproc(int, char*); | |
| 138 | +void flushaction(void*, char*); | |
| 139 | +void pushfcall(char*); | |
| 140 | +Qidtab* uniqueqid(Dir*); | |
| 141 | +void freeqid(Qidtab*); | |
| 142 | +char* estrdup(char*); | |
| 143 | +void* emallocz(uint); | |
| 144 | +int readmessage(int, char*, int); | |
| 145 | + | |
| 146 | +#define notify | |
| 147 | +#define noted | |
| 148 | +#define exits | |
| @@ -0,0 +1,679 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <fcall.h> | |
| 4 | +#define Extern extern | |
| 5 | +#include "exportfs.h" | |
| 6 | + | |
| 7 | +char Ebadfid[] = "Bad fid"; | |
| 8 | +char Enotdir[] = "Not a directory"; | |
| 9 | +char Edupfid[] = "Fid already in use"; | |
| 10 | +char Eopen[] = "Fid already opened"; | |
| 11 | +char Exmnt[] = "Cannot .. past mount point"; | |
| 12 | +char Emip[] = "Mount in progress"; | |
| 13 | +char Enopsmt[] = "Out of pseudo mount points"; | |
| 14 | +char Enomem[] = "No memory"; | |
| 15 | +char Eversion[] = "Bad 9P2000 version"; | |
| 16 | + | |
| 17 | +int iounit(int x) | |
| 18 | +{ | |
| 19 | + return 8192+IOHDRSZ; | |
| 20 | +} | |
| 21 | + | |
| 22 | +void* | |
| 23 | +emallocz(ulong n) | |
| 24 | +{ | |
| 25 | + void *v; | |
| 26 | + | |
| 27 | + v = mallocz(n, 1); | |
| 28 | + if(v == nil) | |
| 29 | + panic("out of memory"); | |
| 30 | + return v; | |
| 31 | +} | |
| 32 | + | |
| 33 | +ulong messagesize; | |
| 34 | + | |
| 35 | +void | |
| 36 | +Xversion(Fsrpc *t) | |
| 37 | +{ | |
| 38 | + Fcall rhdr; | |
| 39 | + | |
| 40 | + if(t->work.msize > messagesize) | |
| 41 | + t->work.msize = messagesize; | |
| 42 | + messagesize = t->work.msize; | |
| 43 | + if(strncmp(t->work.version, "9P2000", 6) != 0){ | |
| 44 | + reply(&t->work, &rhdr, Eversion); | |
| 45 | + return; | |
| 46 | + } | |
| 47 | + rhdr.version = "9P2000"; | |
| 48 | + rhdr.msize = t->work.msize; | |
| 49 | + reply(&t->work, &rhdr, 0); | |
| 50 | + t->busy = 0; | |
| 51 | +} | |
| 52 | + | |
| 53 | +void | |
| 54 | +Xauth(Fsrpc *t) | |
| 55 | +{ | |
| 56 | + Fcall rhdr; | |
| 57 | + | |
| 58 | + reply(&t->work, &rhdr, "exportfs: authentication not required"); | |
| 59 | + t->busy = 0; | |
| 60 | +} | |
| 61 | + | |
| 62 | +void | |
| 63 | +Xflush(Fsrpc *t) | |
| 64 | +{ | |
| 65 | + Fsrpc *w, *e; | |
| 66 | + Fcall rhdr; | |
| 67 | + | |
| 68 | + e = &Workq[Nr_workbufs]; | |
| 69 | + | |
| 70 | + for(w = Workq; w < e; w++) { | |
| 71 | + if(w->work.tag == t->work.oldtag) { | |
| 72 | + DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint); | |
| 73 | + if(w->busy && w->pid) { | |
| 74 | + w->flushtag = t->work.tag; | |
| 75 | + DEBUG(DFD, "\tset flushtag %d\n", t->work.tag); | |
| 76 | + // if(w->canint) | |
| 77 | + // postnote(PNPROC, w->pid, "flush"); | |
| 78 | + t->busy = 0; | |
| 79 | + return; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + } | |
| 83 | + | |
| 84 | + reply(&t->work, &rhdr, 0); | |
| 85 | + DEBUG(DFD, "\tflush reply\n"); | |
| 86 | + t->busy = 0; | |
| 87 | +} | |
| 88 | + | |
| 89 | +void | |
| 90 | +Xattach(Fsrpc *t) | |
| 91 | +{ | |
| 92 | + int i, nfd; | |
| 93 | + Fcall rhdr; | |
| 94 | + Fid *f; | |
| 95 | + char buf[128]; | |
| 96 | + | |
| 97 | + f = newfid(t->work.fid); | |
| 98 | + if(f == 0) { | |
| 99 | + reply(&t->work, &rhdr, Ebadfid); | |
| 100 | + t->busy = 0; | |
| 101 | + return; | |
| 102 | + } | |
| 103 | + | |
| 104 | + if(srvfd >= 0){ | |
| 105 | +/* | |
| 106 | + if(psmpt == 0){ | |
| 107 | + Nomount: | |
| 108 | + reply(&t->work, &rhdr, Enopsmt); | |
| 109 | + t->busy = 0; | |
| 110 | + freefid(t->work.fid); | |
| 111 | + return; | |
| 112 | + } | |
| 113 | + for(i=0; i<Npsmpt; i++) | |
| 114 | + if(psmap[i] == 0) | |
| 115 | + break; | |
| 116 | + if(i >= Npsmpt) | |
| 117 | + goto Nomount; | |
| 118 | + sprint(buf, "%d", i); | |
| 119 | + f->f = file(psmpt, buf); | |
| 120 | + if(f->f == nil) | |
| 121 | + goto Nomount; | |
| 122 | + sprint(buf, "/mnt/exportfs/%d", i); | |
| 123 | + nfd = dup(srvfd, -1); | |
| 124 | + if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){ | |
| 125 | + errstr(buf, sizeof buf); | |
| 126 | + reply(&t->work, &rhdr, buf); | |
| 127 | + t->busy = 0; | |
| 128 | + freefid(t->work.fid); | |
| 129 | + close(nfd); | |
| 130 | + return; | |
| 131 | + } | |
| 132 | + psmap[i] = 1; | |
| 133 | + f->mid = i; | |
| 134 | +*/ | |
| 135 | + }else{ | |
| 136 | + f->f = root; | |
| 137 | + f->f->ref++; | |
| 138 | + } | |
| 139 | + | |
| 140 | + rhdr.qid = f->f->qid; | |
| 141 | + reply(&t->work, &rhdr, 0); | |
| 142 | + t->busy = 0; | |
| 143 | +} | |
| 144 | + | |
| 145 | +Fid* | |
| 146 | +clonefid(Fid *f, int new) | |
| 147 | +{ | |
| 148 | + Fid *n; | |
| 149 | + | |
| 150 | + n = newfid(new); | |
| 151 | + if(n == 0) { | |
| 152 | + n = getfid(new); | |
| 153 | + if(n == 0) | |
| 154 | + fatal("inconsistent fids"); | |
| 155 | + if(n->fid >= 0) | |
| 156 | + close(n->fid); | |
| 157 | + freefid(new); | |
| 158 | + n = newfid(new); | |
| 159 | + if(n == 0) | |
| 160 | + fatal("inconsistent fids2"); | |
| 161 | + } | |
| 162 | + n->f = f->f; | |
| 163 | + n->f->ref++; | |
| 164 | + return n; | |
| 165 | +} | |
| 166 | + | |
| 167 | +void | |
| 168 | +Xwalk(Fsrpc *t) | |
| 169 | +{ | |
| 170 | + char err[ERRMAX], *e; | |
| 171 | + Fcall rhdr; | |
| 172 | + Fid *f, *nf; | |
| 173 | + File *wf; | |
| 174 | + int i; | |
| 175 | + | |
| 176 | + f = getfid(t->work.fid); | |
| 177 | + if(f == 0) { | |
| 178 | + reply(&t->work, &rhdr, Ebadfid); | |
| 179 | + t->busy = 0; | |
| 180 | + return; | |
| 181 | + } | |
| 182 | + | |
| 183 | + nf = nil; | |
| 184 | + if(t->work.newfid != t->work.fid){ | |
| 185 | + nf = clonefid(f, t->work.newfid); | |
| 186 | + f = nf; | |
| 187 | + } | |
| 188 | + | |
| 189 | + rhdr.nwqid = 0; | |
| 190 | + e = nil; | |
| 191 | + for(i=0; i<t->work.nwname; i++){ | |
| 192 | + if(i == MAXWELEM){ | |
| 193 | + e = "Too many path elements"; | |
| 194 | + break; | |
| 195 | + } | |
| 196 | + | |
| 197 | + if(strcmp(t->work.wname[i], "..") == 0) { | |
| 198 | + if(f->f->parent == nil) { | |
| 199 | + e = Exmnt; | |
| 200 | + break; | |
| 201 | + } | |
| 202 | + wf = f->f->parent; | |
| 203 | + wf->ref++; | |
| 204 | + goto Accept; | |
| 205 | + } | |
| 206 | + | |
| 207 | + wf = file(f->f, t->work.wname[i]); | |
| 208 | + if(wf == 0){ | |
| 209 | + errstr(err, sizeof err); | |
| 210 | + e = err; | |
| 211 | + break; | |
| 212 | + } | |
| 213 | + Accept: | |
| 214 | + freefile(f->f); | |
| 215 | + rhdr.wqid[rhdr.nwqid++] = wf->qid; | |
| 216 | + f->f = wf; | |
| 217 | + continue; | |
| 218 | + } | |
| 219 | + | |
| 220 | + if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname)) | |
| 221 | + freefid(t->work.newfid); | |
| 222 | + if(rhdr.nwqid > 0) | |
| 223 | + e = nil; | |
| 224 | + reply(&t->work, &rhdr, e); | |
| 225 | + t->busy = 0; | |
| 226 | +} | |
| 227 | + | |
| 228 | +void | |
| 229 | +Xclunk(Fsrpc *t) | |
| 230 | +{ | |
| 231 | + Fcall rhdr; | |
| 232 | + Fid *f; | |
| 233 | + | |
| 234 | + f = getfid(t->work.fid); | |
| 235 | + if(f == 0) { | |
| 236 | + reply(&t->work, &rhdr, Ebadfid); | |
| 237 | + t->busy = 0; | |
| 238 | + return; | |
| 239 | + } | |
| 240 | + | |
| 241 | + if(f->fid >= 0) | |
| 242 | + close(f->fid); | |
| 243 | + | |
| 244 | + freefid(t->work.fid); | |
| 245 | + reply(&t->work, &rhdr, 0); | |
| 246 | + t->busy = 0; | |
| 247 | +} | |
| 248 | + | |
| 249 | +void | |
| 250 | +Xstat(Fsrpc *t) | |
| 251 | +{ | |
| 252 | + char err[ERRMAX], *path; | |
| 253 | + Fcall rhdr; | |
| 254 | + Fid *f; | |
| 255 | + Dir *d; | |
| 256 | + int s; | |
| 257 | + uchar *statbuf; | |
| 258 | + | |
| 259 | + f = getfid(t->work.fid); | |
| 260 | + if(f == 0) { | |
| 261 | + reply(&t->work, &rhdr, Ebadfid); | |
| 262 | + t->busy = 0; | |
| 263 | + return; | |
| 264 | + } | |
| 265 | + if(f->fid >= 0) | |
| 266 | + d = dirfstat(f->fid); | |
| 267 | + else { | |
| 268 | + path = makepath(f->f, ""); | |
| 269 | + d = dirstat(path); | |
| 270 | + free(path); | |
| 271 | + } | |
| 272 | + | |
| 273 | + if(d == nil) { | |
| 274 | + errstr(err, sizeof err); | |
| 275 | + reply(&t->work, &rhdr, err); | |
| 276 | + t->busy = 0; | |
| 277 | + return; | |
| 278 | + } | |
| 279 | + | |
| 280 | + d->qid.path = f->f->qidt->uniqpath; | |
| 281 | + s = sizeD2M(d); | |
| 282 | + statbuf = emallocz(s); | |
| 283 | + s = convD2M(d, statbuf, s); | |
| 284 | + free(d); | |
| 285 | + rhdr.nstat = s; | |
| 286 | + rhdr.stat = statbuf; | |
| 287 | + reply(&t->work, &rhdr, 0); | |
| 288 | + free(statbuf); | |
| 289 | + t->busy = 0; | |
| 290 | +} | |
| 291 | + | |
| 292 | +static int | |
| 293 | +getiounit(int fd) | |
| 294 | +{ | |
| 295 | + int n; | |
| 296 | + | |
| 297 | + n = iounit(fd); | |
| 298 | + if(n > messagesize-IOHDRSZ) | |
| 299 | + n = messagesize-IOHDRSZ; | |
| 300 | + return n; | |
| 301 | +} | |
| 302 | + | |
| 303 | +void | |
| 304 | +Xcreate(Fsrpc *t) | |
| 305 | +{ | |
| 306 | + char err[ERRMAX], *path; | |
| 307 | + Fcall rhdr; | |
| 308 | + Fid *f; | |
| 309 | + File *nf; | |
| 310 | + | |
| 311 | + f = getfid(t->work.fid); | |
| 312 | + if(f == 0) { | |
| 313 | + reply(&t->work, &rhdr, Ebadfid); | |
| 314 | + t->busy = 0; | |
| 315 | + return; | |
| 316 | + } | |
| 317 | + | |
| 318 | + | |
| 319 | + path = makepath(f->f, t->work.name); | |
| 320 | + f->fid = create(path, t->work.mode, t->work.perm); | |
| 321 | + free(path); | |
| 322 | + if(f->fid < 0) { | |
| 323 | + errstr(err, sizeof err); | |
| 324 | + reply(&t->work, &rhdr, err); | |
| 325 | + t->busy = 0; | |
| 326 | + return; | |
| 327 | + } | |
| 328 | + | |
| 329 | + nf = file(f->f, t->work.name); | |
| 330 | + if(nf == 0) { | |
| 331 | + errstr(err, sizeof err); | |
| 332 | + reply(&t->work, &rhdr, err); | |
| 333 | + t->busy = 0; | |
| 334 | + return; | |
| 335 | + } | |
| 336 | + | |
| 337 | + f->mode = t->work.mode; | |
| 338 | + freefile(f->f); | |
| 339 | + f->f = nf; | |
| 340 | + rhdr.qid = f->f->qid; | |
| 341 | + rhdr.iounit = getiounit(f->fid); | |
| 342 | + reply(&t->work, &rhdr, 0); | |
| 343 | + t->busy = 0; | |
| 344 | +} | |
| 345 | + | |
| 346 | +void | |
| 347 | +Xremove(Fsrpc *t) | |
| 348 | +{ | |
| 349 | + char err[ERRMAX], *path; | |
| 350 | + Fcall rhdr; | |
| 351 | + Fid *f; | |
| 352 | + | |
| 353 | + f = getfid(t->work.fid); | |
| 354 | + if(f == 0) { | |
| 355 | + reply(&t->work, &rhdr, Ebadfid); | |
| 356 | + t->busy = 0; | |
| 357 | + return; | |
| 358 | + } | |
| 359 | + | |
| 360 | + path = makepath(f->f, ""); | |
| 361 | + DEBUG(DFD, "\tremove: %s\n", path); | |
| 362 | + if(remove(path) < 0) { | |
| 363 | + free(path); | |
| 364 | + errstr(err, sizeof err); | |
| 365 | + reply(&t->work, &rhdr, err); | |
| 366 | + t->busy = 0; | |
| 367 | + return; | |
| 368 | + } | |
| 369 | + free(path); | |
| 370 | + | |
| 371 | + f->f->inval = 1; | |
| 372 | + if(f->fid >= 0) | |
| 373 | + close(f->fid); | |
| 374 | + freefid(t->work.fid); | |
| 375 | + | |
| 376 | + reply(&t->work, &rhdr, 0); | |
| 377 | + t->busy = 0; | |
| 378 | +} | |
| 379 | + | |
| 380 | +void | |
| 381 | +Xwstat(Fsrpc *t) | |
| 382 | +{ | |
| 383 | + char err[ERRMAX], *path; | |
| 384 | + Fcall rhdr; | |
| 385 | + Fid *f; | |
| 386 | + int s; | |
| 387 | + char *strings; | |
| 388 | + Dir d; | |
| 389 | + | |
| 390 | + f = getfid(t->work.fid); | |
| 391 | + if(f == 0) { | |
| 392 | + reply(&t->work, &rhdr, Ebadfid); | |
| 393 | + t->busy = 0; | |
| 394 | + return; | |
| 395 | + } | |
| 396 | + strings = emallocz(t->work.nstat); /* ample */ | |
| 397 | + if(convM2D(t->work.stat, t->work.nstat, &d, strings) < 0){ | |
| 398 | + rerrstr(err, sizeof err); | |
| 399 | + reply(&t->work, &rhdr, err); | |
| 400 | + t->busy = 0; | |
| 401 | + free(strings); | |
| 402 | + return; | |
| 403 | + } | |
| 404 | + | |
| 405 | + if(f->fid >= 0) | |
| 406 | + s = dirfwstat(f->fid, &d); | |
| 407 | + else { | |
| 408 | + path = makepath(f->f, ""); | |
| 409 | + s = dirwstat(path, &d); | |
| 410 | + free(path); | |
| 411 | + } | |
| 412 | + if(s < 0) { | |
| 413 | + rerrstr(err, sizeof err); | |
| 414 | + reply(&t->work, &rhdr, err); | |
| 415 | + } | |
| 416 | + else { | |
| 417 | + /* wstat may really be rename */ | |
| 418 | + if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){ | |
| 419 | + free(f->f->name); | |
| 420 | + f->f->name = estrdup(d.name); | |
| 421 | + } | |
| 422 | + reply(&t->work, &rhdr, 0); | |
| 423 | + } | |
| 424 | + free(strings); | |
| 425 | + t->busy = 0; | |
| 426 | +} | |
| 427 | + | |
| 428 | +void | |
| 429 | +slave(Fsrpc *f) | |
| 430 | +{ | |
| 431 | + Proc *p; | |
| 432 | + int pid; | |
| 433 | + static int nproc; | |
| 434 | + | |
| 435 | + for(;;) { | |
| 436 | + for(p = Proclist; p; p = p->next) { | |
| 437 | + if(p->busy == 0) { | |
| 438 | + f->pid = p->pid; | |
| 439 | + p->busy = 1; | |
| 440 | + pid = rendezvous(p->pid, (ulong)f); | |
| 441 | + if(pid != p->pid) | |
| 442 | + fatal("rendezvous sync fail"); | |
| 443 | + return; | |
| 444 | + } | |
| 445 | + } | |
| 446 | + | |
| 447 | + if(++nproc > MAXPROC) | |
| 448 | + fatal("too many procs"); | |
| 449 | + | |
| 450 | + pid = kproc("slave", blockingslave, nil); | |
| 451 | + DEBUG(DFD, "slave pid %d\n", pid); | |
| 452 | + if(pid == -1) | |
| 453 | + fatal("kproc"); | |
| 454 | + | |
| 455 | + p = malloc(sizeof(Proc)); | |
| 456 | + if(p == 0) | |
| 457 | + fatal("out of memory"); | |
| 458 | + | |
| 459 | + p->busy = 0; | |
| 460 | + p->pid = pid; | |
| 461 | + p->next = Proclist; | |
| 462 | + Proclist = p; | |
| 463 | + | |
| 464 | +DEBUG(DFD, "parent %d rendez\n", pid); | |
| 465 | + rendezvous(pid, (ulong)p); | |
| 466 | +DEBUG(DFD, "parent %d went\n", pid); | |
| 467 | + } | |
| 468 | +} | |
| 469 | + | |
| 470 | +void | |
| 471 | +blockingslave(void *x) | |
| 472 | +{ | |
| 473 | + Fsrpc *p; | |
| 474 | + Fcall rhdr; | |
| 475 | + Proc *m; | |
| 476 | + int pid; | |
| 477 | + | |
| 478 | + USED(x); | |
| 479 | + | |
| 480 | + notify(flushaction); | |
| 481 | + | |
| 482 | + pid = getpid(); | |
| 483 | + | |
| 484 | +DEBUG(DFD, "blockingslave %d rendez\n", pid); | |
| 485 | + m = (Proc*)rendezvous(pid, 0); | |
| 486 | +DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m); | |
| 487 | + | |
| 488 | + for(;;) { | |
| 489 | + p = (Fsrpc*)rendezvous(pid, pid); | |
| 490 | + if((int)p == ~0) /* Interrupted */ | |
| 491 | + continue; | |
| 492 | + | |
| 493 | + DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid); | |
| 494 | + if(p->flushtag != NOTAG) | |
| 495 | + goto flushme; | |
| 496 | + | |
| 497 | + switch(p->work.type) { | |
| 498 | + case Tread: | |
| 499 | + slaveread(p); | |
| 500 | + break; | |
| 501 | + | |
| 502 | + case Twrite: | |
| 503 | + slavewrite(p); | |
| 504 | + break; | |
| 505 | + | |
| 506 | + case Topen: | |
| 507 | + slaveopen(p); | |
| 508 | + break; | |
| 509 | + | |
| 510 | + default: | |
| 511 | + reply(&p->work, &rhdr, "exportfs: slave type error"); | |
| 512 | + } | |
| 513 | + if(p->flushtag != NOTAG) { | |
| 514 | +flushme: | |
| 515 | + p->work.type = Tflush; | |
| 516 | + p->work.tag = p->flushtag; | |
| 517 | + reply(&p->work, &rhdr, 0); | |
| 518 | + } | |
| 519 | + p->busy = 0; | |
| 520 | + m->busy = 0; | |
| 521 | + } | |
| 522 | +} | |
| 523 | + | |
| 524 | +int | |
| 525 | +openmount(int sfd) | |
| 526 | +{ | |
| 527 | + werrstr("openmount not implemented"); | |
| 528 | + return -1; | |
| 529 | +} | |
| 530 | + | |
| 531 | +void | |
| 532 | +slaveopen(Fsrpc *p) | |
| 533 | +{ | |
| 534 | + char err[ERRMAX], *path; | |
| 535 | + Fcall *work, rhdr; | |
| 536 | + Fid *f; | |
| 537 | + Dir *d; | |
| 538 | + | |
| 539 | + work = &p->work; | |
| 540 | + | |
| 541 | + f = getfid(work->fid); | |
| 542 | + if(f == 0) { | |
| 543 | + reply(work, &rhdr, Ebadfid); | |
| 544 | + return; | |
| 545 | + } | |
| 546 | + if(f->fid >= 0) { | |
| 547 | + close(f->fid); | |
| 548 | + f->fid = -1; | |
| 549 | + } | |
| 550 | + | |
| 551 | + path = makepath(f->f, ""); | |
| 552 | + DEBUG(DFD, "\topen: %s %d\n", path, work->mode); | |
| 553 | + | |
| 554 | + p->canint = 1; | |
| 555 | + if(p->flushtag != NOTAG){ | |
| 556 | + free(path); | |
| 557 | + return; | |
| 558 | + } | |
| 559 | + /* There is a race here I ignore because there are no locks */ | |
| 560 | + f->fid = open(path, work->mode); | |
| 561 | + free(path); | |
| 562 | + p->canint = 0; | |
| 563 | + if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) { | |
| 564 | + Error: | |
| 565 | + errstr(err, sizeof err); | |
| 566 | + reply(work, &rhdr, err); | |
| 567 | + return; | |
| 568 | + } | |
| 569 | + f->f->qid = d->qid; | |
| 570 | + free(d); | |
| 571 | + if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */ | |
| 572 | + f->fid = openmount(f->fid); | |
| 573 | + if(f->fid < 0) | |
| 574 | + goto Error; | |
| 575 | + } | |
| 576 | + | |
| 577 | + DEBUG(DFD, "\topen: fd %d\n", f->fid); | |
| 578 | + f->mode = work->mode; | |
| 579 | + rhdr.iounit = getiounit(f->fid); | |
| 580 | + rhdr.qid = f->f->qid; | |
| 581 | + reply(work, &rhdr, 0); | |
| 582 | +} | |
| 583 | + | |
| 584 | +void | |
| 585 | +slaveread(Fsrpc *p) | |
| 586 | +{ | |
| 587 | + Fid *f; | |
| 588 | + int n, r; | |
| 589 | + Fcall *work, rhdr; | |
| 590 | + char *data, err[ERRMAX]; | |
| 591 | + | |
| 592 | + work = &p->work; | |
| 593 | + | |
| 594 | + f = getfid(work->fid); | |
| 595 | + if(f == 0) { | |
| 596 | + reply(work, &rhdr, Ebadfid); | |
| 597 | + return; | |
| 598 | + } | |
| 599 | + | |
| 600 | + n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; | |
| 601 | + p->canint = 1; | |
| 602 | + if(p->flushtag != NOTAG) | |
| 603 | + return; | |
| 604 | + data = malloc(n); | |
| 605 | + if(data == nil) | |
| 606 | + fatal(Enomem); | |
| 607 | + | |
| 608 | + /* can't just call pread, since directories must update the offset */ | |
| 609 | + r = pread(f->fid, data, n, work->offset); | |
| 610 | + p->canint = 0; | |
| 611 | + if(r < 0) { | |
| 612 | + free(data); | |
| 613 | + errstr(err, sizeof err); | |
| 614 | + reply(work, &rhdr, err); | |
| 615 | + return; | |
| 616 | + } | |
| 617 | + | |
| 618 | + DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r); | |
| 619 | + | |
| 620 | + rhdr.data = data; | |
| 621 | + rhdr.count = r; | |
| 622 | + reply(work, &rhdr, 0); | |
| 623 | + free(data); | |
| 624 | +} | |
| 625 | + | |
| 626 | +void | |
| 627 | +slavewrite(Fsrpc *p) | |
| 628 | +{ | |
| 629 | + char err[ERRMAX]; | |
| 630 | + Fcall *work, rhdr; | |
| 631 | + Fid *f; | |
| 632 | + int n; | |
| 633 | + | |
| 634 | + work = &p->work; | |
| 635 | + | |
| 636 | + f = getfid(work->fid); | |
| 637 | + if(f == 0) { | |
| 638 | + reply(work, &rhdr, Ebadfid); | |
| 639 | + return; | |
| 640 | + } | |
| 641 | + | |
| 642 | + n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count; | |
| 643 | + p->canint = 1; | |
| 644 | + if(p->flushtag != NOTAG) | |
| 645 | + return; | |
| 646 | + n = pwrite(f->fid, work->data, n, work->offset); | |
| 647 | + p->canint = 0; | |
| 648 | + if(n < 0) { | |
| 649 | + errstr(err, sizeof err); | |
| 650 | + reply(work, &rhdr, err); | |
| 651 | + return; | |
| 652 | + } | |
| 653 | + | |
| 654 | + DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid); | |
| 655 | + | |
| 656 | + rhdr.count = n; | |
| 657 | + reply(work, &rhdr, 0); | |
| 658 | +} | |
| 659 | + | |
| 660 | +void | |
| 661 | +reopen(Fid *f) | |
| 662 | +{ | |
| 663 | + USED(f); | |
| 664 | + fatal("reopen"); | |
| 665 | +} | |
| 666 | + | |
| 667 | +void | |
| 668 | +flushaction(void *a, char *cause) | |
| 669 | +{ | |
| 670 | + USED(a); | |
| 671 | + if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) { | |
| 672 | + fprint(2, "exportsrv: note: %s\n", cause); | |
| 673 | + exits("noted"); | |
| 674 | + } | |
| 675 | + if(strncmp(cause, "kill", 4) == 0) | |
| 676 | + noted(NDFLT); | |
| 677 | + | |
| 678 | + noted(NCONT); | |
| 679 | +} | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +<$DSRC/mkfile-$CONF | |
| 2 | +TARG=libexportfs.$L | |
| 3 | + | |
| 4 | +OFILES=\ | |
| 5 | + exportfs.$O\ | |
| 6 | + exportsrv.$O | |
| 7 | + | |
| 8 | +HFILES=\ | |
| 9 | + exportfs.h | |
| 10 | + | |
| 11 | +<$DSRC/mklib-$CONF | |
| @@ -0,0 +1,23 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | + | |
| 6 | +Memimage* | |
| 7 | +allocmemimage(Rectangle r, ulong chan) | |
| 8 | +{ | |
| 9 | + return _allocmemimage(r, chan); | |
| 10 | +} | |
| 11 | + | |
| 12 | +void | |
| 13 | +freememimage(Memimage *i) | |
| 14 | +{ | |
| 15 | + _freememimage(i); | |
| 16 | +} | |
| 17 | + | |
| 18 | +void | |
| 19 | +memfillcolor(Memimage *i, ulong val) | |
| 20 | +{ | |
| 21 | + _memfillcolor(i, val); | |
| 22 | +} | |
| 23 | + | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | + | |
| 6 | +int | |
| 7 | +cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) | |
| 8 | +{ | |
| 9 | + return _cloadmemimage(i, r, data, ndata); | |
| 10 | +} | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | + | |
| 6 | +void | |
| 7 | +memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) | |
| 8 | +{ | |
| 9 | + _memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op)); | |
| 10 | +} | |
| 11 | + | |
| 12 | +ulong | |
| 13 | +pixelbits(Memimage *m, Point p) | |
| 14 | +{ | |
| 15 | + return _pixelbits(m, p); | |
| 16 | +} | |
| 17 | + | |
| 18 | +void | |
| 19 | +memimageinit(void) | |
| 20 | +{ | |
| 21 | + _memimageinit(); | |
| 22 | +} | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | + | |
| 6 | +int | |
| 7 | +loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) | |
| 8 | +{ | |
| 9 | + return _loadmemimage(i, r, data, ndata); | |
| 10 | +} | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +<$DSRC/mkfile-$CONF | |
| 2 | +TARG=libgui.$L | |
| 3 | + | |
| 4 | +OFILES=\ | |
| 5 | + alloc.$O\ | |
| 6 | + cload.$O\ | |
| 7 | + draw.$O\ | |
| 8 | + load.$O\ | |
| 9 | + screen.$O\ | |
| 10 | + wstrtoutf.$O | |
| 11 | + | |
| 12 | +HFILES=\ | |
| 13 | + | |
| 14 | +<$DSRC/mklib-$CONF | |
| @@ -0,0 +1,642 @@ | ||
| 1 | +#include <windows.h> | |
| 2 | +// #include "winduhz.h" | |
| 3 | + | |
| 4 | +#undef Rectangle | |
| 5 | +#define Rectangle _Rectangle | |
| 6 | + | |
| 7 | +#include <u.h> | |
| 8 | +#include <libc.h> | |
| 9 | +#include <dat.h> | |
| 10 | +#include <draw.h> | |
| 11 | +#include <memdraw.h> | |
| 12 | +#include "error.h" | |
| 13 | +#include "screen.h" | |
| 14 | +#include "keyboard.h" | |
| 15 | +#include "fns.h" | |
| 16 | + | |
| 17 | +Memimage *gscreen; | |
| 18 | +Screeninfo screen; | |
| 19 | + | |
| 20 | +extern int mousequeue; | |
| 21 | +static int depth; | |
| 22 | + | |
| 23 | +static HINSTANCE inst; | |
| 24 | +static HWND window; | |
| 25 | +static HPALETTE palette; | |
| 26 | +static LOGPALETTE *logpal; | |
| 27 | +static Lock gdilock; | |
| 28 | +static BITMAPINFO *bmi; | |
| 29 | +static HCURSOR hcursor; | |
| 30 | + | |
| 31 | +static void winproc(void *); | |
| 32 | +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); | |
| 33 | +static void paletteinit(void); | |
| 34 | +static void bmiinit(void); | |
| 35 | +static void screenload2(Rectangle r, int ldepth, uchar *p, Point pt, int step); | |
| 36 | + | |
| 37 | +static int readybit; | |
| 38 | +static Rendez rend; | |
| 39 | + | |
| 40 | +Point ZP; | |
| 41 | + | |
| 42 | +static | |
| 43 | +isready(void*a) | |
| 44 | +{ | |
| 45 | + return readybit; | |
| 46 | +} | |
| 47 | + | |
| 48 | +void | |
| 49 | +screeninit(void) | |
| 50 | +{ | |
| 51 | + int fmt; | |
| 52 | + int dx, dy; | |
| 53 | + | |
| 54 | + memimageinit(); | |
| 55 | + if(depth == 0) | |
| 56 | + depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL); | |
| 57 | + switch(depth){ | |
| 58 | + case 32: | |
| 59 | + screen.dibtype = DIB_RGB_COLORS; | |
| 60 | + screen.depth = 32; | |
| 61 | + fmt = XRGB32; | |
| 62 | + break; | |
| 63 | + case 24: | |
| 64 | + screen.dibtype = DIB_RGB_COLORS; | |
| 65 | + screen.depth = 24; | |
| 66 | + fmt = RGB24; | |
| 67 | + break; | |
| 68 | + case 16: | |
| 69 | + screen.dibtype = DIB_RGB_COLORS; | |
| 70 | + screen.depth = 16; | |
| 71 | + fmt = RGB15; /* [sic] */ | |
| 72 | + break; | |
| 73 | + case 8: | |
| 74 | + default: | |
| 75 | + screen.dibtype = DIB_PAL_COLORS; | |
| 76 | + screen.depth = 8; | |
| 77 | + depth = 8; | |
| 78 | + fmt = CMAP8; | |
| 79 | + break; | |
| 80 | + } | |
| 81 | + dx = GetDeviceCaps(GetDC(NULL), HORZRES); | |
| 82 | + dy = GetDeviceCaps(GetDC(NULL), VERTRES); | |
| 83 | + | |
| 84 | + gscreen = allocmemimage(Rect(0,0,dx,dy), fmt); | |
| 85 | + kproc("winscreen", winproc, 0); | |
| 86 | + sleep(&rend, isready, 0); | |
| 87 | +} | |
| 88 | + | |
| 89 | +uchar* | |
| 90 | +attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X) | |
| 91 | +{ | |
| 92 | + *r = gscreen->r; | |
| 93 | + *chan = gscreen->chan; | |
| 94 | + *depth = gscreen->depth; | |
| 95 | + *width = gscreen->width; | |
| 96 | + *softscreen = 1; | |
| 97 | + | |
| 98 | + return gscreen->data->bdata; | |
| 99 | +} | |
| 100 | + | |
| 101 | +void | |
| 102 | +flushmemscreen(Rectangle r) | |
| 103 | +{ | |
| 104 | + screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP, | |
| 105 | + gscreen->width*sizeof(ulong)); | |
| 106 | +// Sleep(100); | |
| 107 | +} | |
| 108 | + | |
| 109 | +void | |
| 110 | +screenload(Rectangle r, int depth, uchar *p, Point pt, int step) | |
| 111 | +{ | |
| 112 | + int dx, dy, delx; | |
| 113 | + HDC hdc; | |
| 114 | + RECT winr; | |
| 115 | + | |
| 116 | + if(depth != gscreen->depth) | |
| 117 | + panic("screenload: bad ldepth"); | |
| 118 | + | |
| 119 | + /* | |
| 120 | + * Sometimes we do get rectangles that are off the | |
| 121 | + * screen to the negative axes, for example, when | |
| 122 | + * dragging around a window border in a Move operation. | |
| 123 | + */ | |
| 124 | + if(rectclip(&r, gscreen->r) == 0) | |
| 125 | + return; | |
| 126 | + | |
| 127 | + if(step&3 != 0 || ((pt.x*depth)%32) != 0 || (ulong)p&3 != 0) | |
| 128 | + panic("screenload: bad params %d %d %ux", step, pt.x, p); | |
| 129 | + dx = r.max.x - r.min.x; | |
| 130 | + dy = r.max.y - r.min.y; | |
| 131 | + | |
| 132 | + if(dx <= 0 || dy <= 0) | |
| 133 | + return; | |
| 134 | + | |
| 135 | + if(depth == 24) | |
| 136 | + delx = r.min.x % 4; | |
| 137 | + else | |
| 138 | + delx = r.min.x & (31/depth); | |
| 139 | + | |
| 140 | + p += (r.min.y-pt.y)*step; | |
| 141 | + p += ((r.min.x-delx-pt.x)*depth)>>3; | |
| 142 | + | |
| 143 | + if(GetWindowRect(window, &winr)==0) | |
| 144 | + return; | |
| 145 | + if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0) | |
| 146 | + return; | |
| 147 | + | |
| 148 | + lock(&gdilock); | |
| 149 | + | |
| 150 | + hdc = GetDC(window); | |
| 151 | + SelectPalette(hdc, palette, 0); | |
| 152 | + RealizePalette(hdc); | |
| 153 | + | |
| 154 | +//FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH)); | |
| 155 | +//GdiFlush(); | |
| 156 | +//Sleep(100); | |
| 157 | + | |
| 158 | + bmi->bmiHeader.biWidth = (step*8)/depth; | |
| 159 | + bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */ | |
| 160 | + | |
| 161 | + StretchDIBits(hdc, r.min.x, r.min.y, dx, dy, | |
| 162 | + delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY); | |
| 163 | + | |
| 164 | + ReleaseDC(window, hdc); | |
| 165 | + | |
| 166 | + GdiFlush(); | |
| 167 | + | |
| 168 | + unlock(&gdilock); | |
| 169 | +} | |
| 170 | + | |
| 171 | +static void | |
| 172 | +winproc(void *a) | |
| 173 | +{ | |
| 174 | + WNDCLASS wc; | |
| 175 | + MSG msg; | |
| 176 | + | |
| 177 | + inst = GetModuleHandle(NULL); | |
| 178 | + | |
| 179 | + paletteinit(); | |
| 180 | + bmiinit(); | |
| 181 | + terminit(); | |
| 182 | + | |
| 183 | + wc.style = 0; | |
| 184 | + wc.lpfnWndProc = WindowProc; | |
| 185 | + wc.cbClsExtra = 0; | |
| 186 | + wc.cbWndExtra = 0; | |
| 187 | + wc.hInstance = inst; | |
| 188 | + wc.hIcon = LoadIcon(inst, NULL); | |
| 189 | + wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |
| 190 | + wc.hbrBackground = GetStockObject(WHITE_BRUSH); | |
| 191 | + wc.lpszMenuName = 0; | |
| 192 | + wc.lpszClassName = "9pmgraphics"; | |
| 193 | + RegisterClass(&wc); | |
| 194 | + | |
| 195 | + window = CreateWindowEx( | |
| 196 | + 0, /* extended style */ | |
| 197 | + "9pmgraphics", /* class */ | |
| 198 | + "drawterm screen", /* caption */ | |
| 199 | + WS_OVERLAPPEDWINDOW, /* style */ | |
| 200 | + CW_USEDEFAULT, /* init. x pos */ | |
| 201 | + CW_USEDEFAULT, /* init. y pos */ | |
| 202 | + CW_USEDEFAULT, /* init. x size */ | |
| 203 | + CW_USEDEFAULT, /* init. y size */ | |
| 204 | + NULL, /* parent window (actually owner window for overlapped)*/ | |
| 205 | + NULL, /* menu handle */ | |
| 206 | + inst, /* program handle */ | |
| 207 | + NULL /* create parms */ | |
| 208 | + ); | |
| 209 | + | |
| 210 | + if(window == nil) | |
| 211 | + panic("can't make window\n"); | |
| 212 | + | |
| 213 | + ShowWindow(window, SW_SHOWDEFAULT); | |
| 214 | + UpdateWindow(window); | |
| 215 | + | |
| 216 | + readybit = 1; | |
| 217 | + wakeup(&rend); | |
| 218 | + | |
| 219 | + screen.reshaped = 0; | |
| 220 | + | |
| 221 | + while(GetMessage(&msg, NULL, 0, 0)) { | |
| 222 | + TranslateMessage(&msg); | |
| 223 | + DispatchMessage(&msg); | |
| 224 | + } | |
| 225 | +// MessageBox(0, "winproc", "exits", MB_OK); | |
| 226 | + ExitProcess(0); | |
| 227 | +} | |
| 228 | + | |
| 229 | +int | |
| 230 | +col(int v, int n) | |
| 231 | +{ | |
| 232 | + int i, c; | |
| 233 | + | |
| 234 | + c = 0; | |
| 235 | + for(i = 0; i < 8; i += n) | |
| 236 | + c |= v << (16-(n+i)); | |
| 237 | + return c >> 8; | |
| 238 | +} | |
| 239 | + | |
| 240 | + | |
| 241 | +void | |
| 242 | +paletteinit(void) | |
| 243 | +{ | |
| 244 | + PALETTEENTRY *pal; | |
| 245 | + int r, g, b, cr, cg, cb, v; | |
| 246 | + int num, den; | |
| 247 | + int i, j; | |
| 248 | + | |
| 249 | + logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1); | |
| 250 | + if(logpal == nil) | |
| 251 | + panic("out of memory"); | |
| 252 | + logpal->palVersion = 0x300; | |
| 253 | + logpal->palNumEntries = 256; | |
| 254 | + pal = logpal->palPalEntry; | |
| 255 | + | |
| 256 | + for(r=0,i=0; r<4; r++) { | |
| 257 | + for(v=0; v<4; v++,i+=16){ | |
| 258 | + for(g=0,j=v-r; g<4; g++) { | |
| 259 | + for(b=0; b<4; b++,j++){ | |
| 260 | + den=r; | |
| 261 | + if(g>den) | |
| 262 | + den=g; | |
| 263 | + if(b>den) | |
| 264 | + den=b; | |
| 265 | + /* divide check -- pick grey shades */ | |
| 266 | + if(den==0) | |
| 267 | + cr=cg=cb=v*17; | |
| 268 | + else{ | |
| 269 | + num=17*(4*den+v); | |
| 270 | + cr=r*num/den; | |
| 271 | + cg=g*num/den; | |
| 272 | + cb=b*num/den; | |
| 273 | + } | |
| 274 | + pal[i+(j&15)].peRed = cr; | |
| 275 | + pal[i+(j&15)].peGreen = cg; | |
| 276 | + pal[i+(j&15)].peBlue = cb; | |
| 277 | + pal[i+(j&15)].peFlags = 0; | |
| 278 | + } | |
| 279 | + } | |
| 280 | + } | |
| 281 | + } | |
| 282 | + palette = CreatePalette(logpal); | |
| 283 | +} | |
| 284 | + | |
| 285 | + | |
| 286 | +void | |
| 287 | +getcolor(ulong i, ulong *r, ulong *g, ulong *b) | |
| 288 | +{ | |
| 289 | + PALETTEENTRY *pal; | |
| 290 | + | |
| 291 | + pal = logpal->palPalEntry; | |
| 292 | + *r = pal[i].peRed; | |
| 293 | + *g = pal[i].peGreen; | |
| 294 | + *b = pal[i].peBlue; | |
| 295 | +} | |
| 296 | + | |
| 297 | +void | |
| 298 | +bmiinit(void) | |
| 299 | +{ | |
| 300 | + ushort *p; | |
| 301 | + int i; | |
| 302 | + | |
| 303 | + bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1); | |
| 304 | + if(bmi == 0) | |
| 305 | + panic("out of memory"); | |
| 306 | + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
| 307 | + bmi->bmiHeader.biWidth = 0; | |
| 308 | + bmi->bmiHeader.biHeight = 0; /* - => origin upper left */ | |
| 309 | + bmi->bmiHeader.biPlanes = 1; | |
| 310 | + bmi->bmiHeader.biBitCount = depth; | |
| 311 | + bmi->bmiHeader.biCompression = BI_RGB; | |
| 312 | + bmi->bmiHeader.biSizeImage = 0; | |
| 313 | + bmi->bmiHeader.biXPelsPerMeter = 0; | |
| 314 | + bmi->bmiHeader.biYPelsPerMeter = 0; | |
| 315 | + bmi->bmiHeader.biClrUsed = 0; | |
| 316 | + bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */ | |
| 317 | + | |
| 318 | + p = (ushort*)bmi->bmiColors; | |
| 319 | + for(i = 0; i < 256; i++) | |
| 320 | + p[i] = i; | |
| 321 | +} | |
| 322 | + | |
| 323 | +LRESULT CALLBACK | |
| 324 | +WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | |
| 325 | +{ | |
| 326 | + PAINTSTRUCT paint; | |
| 327 | + HDC hdc; | |
| 328 | + LONG x, y, b; | |
| 329 | + int i; | |
| 330 | + Rectangle r; | |
| 331 | + | |
| 332 | + switch(msg) { | |
| 333 | + case WM_CREATE: | |
| 334 | + break; | |
| 335 | + case WM_SETCURSOR: | |
| 336 | + /* User set */ | |
| 337 | + if(hcursor != NULL) { | |
| 338 | + SetCursor(hcursor); | |
| 339 | + return 1; | |
| 340 | + } | |
| 341 | + return DefWindowProc(hwnd, msg, wparam, lparam); | |
| 342 | + case WM_MOUSEMOVE: | |
| 343 | + case WM_LBUTTONUP: | |
| 344 | + case WM_MBUTTONUP: | |
| 345 | + case WM_RBUTTONUP: | |
| 346 | + case WM_LBUTTONDOWN: | |
| 347 | + case WM_MBUTTONDOWN: | |
| 348 | + case WM_RBUTTONDOWN: | |
| 349 | + x = LOWORD(lparam); | |
| 350 | + y = HIWORD(lparam); | |
| 351 | + b = 0; | |
| 352 | + if(wparam & MK_LBUTTON) | |
| 353 | + b = 1; | |
| 354 | + if(wparam & MK_MBUTTON) | |
| 355 | + b |= 2; | |
| 356 | + if(wparam & MK_RBUTTON) { | |
| 357 | + if(wparam & MK_SHIFT) | |
| 358 | + b |= 2; | |
| 359 | + else | |
| 360 | + b |= 4; | |
| 361 | + } | |
| 362 | + lock(&mouse.lk); | |
| 363 | + i = mouse.wi; | |
| 364 | + if(mousequeue) { | |
| 365 | + if(i == mouse.ri || mouse.lastb != b || mouse.trans) { | |
| 366 | + mouse.wi = (i+1)%Mousequeue; | |
| 367 | + if(mouse.wi == mouse.ri) | |
| 368 | + mouse.ri = (mouse.ri+1)%Mousequeue; | |
| 369 | + mouse.trans = mouse.lastb != b; | |
| 370 | + } else { | |
| 371 | + i = (i-1+Mousequeue)%Mousequeue; | |
| 372 | + } | |
| 373 | + } else { | |
| 374 | + mouse.wi = (i+1)%Mousequeue; | |
| 375 | + mouse.ri = i; | |
| 376 | + } | |
| 377 | + mouse.queue[i].xy.x = x; | |
| 378 | + mouse.queue[i].xy.y = y; | |
| 379 | + mouse.queue[i].buttons = b; | |
| 380 | + mouse.queue[i].msec = ticks(); | |
| 381 | + mouse.lastb = b; | |
| 382 | + unlock(&mouse.lk); | |
| 383 | + wakeup(&mouse.r); | |
| 384 | + break; | |
| 385 | + | |
| 386 | + case WM_CHAR: | |
| 387 | + /* repeat count is lparam & 0xf */ | |
| 388 | + switch(wparam){ | |
| 389 | + case '\n': | |
| 390 | + wparam = '\r'; | |
| 391 | + break; | |
| 392 | + case '\r': | |
| 393 | + wparam = '\n'; | |
| 394 | + break; | |
| 395 | + } | |
| 396 | + kbdputc(kbdq, wparam); | |
| 397 | + break; | |
| 398 | + | |
| 399 | + case WM_SYSKEYUP: | |
| 400 | + break; | |
| 401 | + case WM_SYSKEYDOWN: | |
| 402 | + case WM_KEYDOWN: | |
| 403 | + switch(wparam) { | |
| 404 | + case VK_MENU: | |
| 405 | + kbdputc(kbdq, Kalt); | |
| 406 | + break; | |
| 407 | + case VK_INSERT: | |
| 408 | + kbdputc(kbdq, Kins); | |
| 409 | + break; | |
| 410 | + case VK_DELETE: | |
| 411 | +// kbdputc(kbdq, Kdel); | |
| 412 | + kbdputc(kbdq, 0x7f); // should have Kdel in keyboard.h | |
| 413 | + break; | |
| 414 | + case VK_UP: | |
| 415 | + kbdputc(kbdq, Kup); | |
| 416 | + break; | |
| 417 | + case VK_DOWN: | |
| 418 | + kbdputc(kbdq, Kdown); | |
| 419 | + break; | |
| 420 | + case VK_LEFT: | |
| 421 | + kbdputc(kbdq, Kleft); | |
| 422 | + break; | |
| 423 | + case VK_RIGHT: | |
| 424 | + kbdputc(kbdq, Kright); | |
| 425 | + break; | |
| 426 | + } | |
| 427 | + break; | |
| 428 | + | |
| 429 | + case WM_CLOSE: | |
| 430 | + DestroyWindow(hwnd); | |
| 431 | + break; | |
| 432 | + | |
| 433 | + case WM_DESTROY: | |
| 434 | + PostQuitMessage(0); | |
| 435 | + break; | |
| 436 | + | |
| 437 | + case WM_PALETTECHANGED: | |
| 438 | + if((HWND)wparam == hwnd) | |
| 439 | + break; | |
| 440 | + /* fall through */ | |
| 441 | + case WM_QUERYNEWPALETTE: | |
| 442 | + hdc = GetDC(hwnd); | |
| 443 | + SelectPalette(hdc, palette, 0); | |
| 444 | + if(RealizePalette(hdc) != 0) | |
| 445 | + InvalidateRect(hwnd, nil, 0); | |
| 446 | + ReleaseDC(hwnd, hdc); | |
| 447 | + break; | |
| 448 | + | |
| 449 | + case WM_PAINT: | |
| 450 | + hdc = BeginPaint(hwnd, &paint); | |
| 451 | + r.min.x = paint.rcPaint.left; | |
| 452 | + r.min.y = paint.rcPaint.top; | |
| 453 | + r.max.x = paint.rcPaint.right; | |
| 454 | + r.max.y = paint.rcPaint.bottom; | |
| 455 | + flushmemscreen(r); | |
| 456 | + EndPaint(hwnd, &paint); | |
| 457 | + break; | |
| 458 | + case WM_COMMAND: | |
| 459 | + case WM_SETFOCUS: | |
| 460 | + case WM_DEVMODECHANGE: | |
| 461 | + case WM_WININICHANGE: | |
| 462 | + case WM_INITMENU: | |
| 463 | + default: | |
| 464 | + return DefWindowProc(hwnd, msg, wparam, lparam); | |
| 465 | + } | |
| 466 | + return 0; | |
| 467 | +} | |
| 468 | + | |
| 469 | +void | |
| 470 | +mouseset(Point xy) | |
| 471 | +{ | |
| 472 | + POINT pt; | |
| 473 | + | |
| 474 | + pt.x = xy.x; | |
| 475 | + pt.y = xy.y; | |
| 476 | + MapWindowPoints(window, 0, &pt, 1); | |
| 477 | + SetCursorPos(pt.x, pt.y); | |
| 478 | +} | |
| 479 | + | |
| 480 | +void | |
| 481 | +setcursor(void) | |
| 482 | +{ | |
| 483 | + HCURSOR nh; | |
| 484 | + int x, y, h, w; | |
| 485 | + uchar *sp, *cp; | |
| 486 | + uchar *and, *xor; | |
| 487 | + | |
| 488 | + h = GetSystemMetrics(SM_CYCURSOR); | |
| 489 | + w = (GetSystemMetrics(SM_CXCURSOR)+7)/8; | |
| 490 | + | |
| 491 | + and = mallocz(h*w, 1); | |
| 492 | + memset(and, 0xff, h*w); | |
| 493 | + xor = mallocz(h*w, 1); | |
| 494 | + | |
| 495 | + lock(&cursor.lk); | |
| 496 | + for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) { | |
| 497 | + for(x=0; x<2; x++) { | |
| 498 | + and[y*w+x] = ~(*sp|*cp); | |
| 499 | + xor[y*w+x] = ~*sp & *cp; | |
| 500 | + cp++; | |
| 501 | + sp++; | |
| 502 | + } | |
| 503 | + } | |
| 504 | + nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y, | |
| 505 | + GetSystemMetrics(SM_CXCURSOR), h, | |
| 506 | + and, xor); | |
| 507 | + if(nh != NULL) { | |
| 508 | + SetCursor(nh); | |
| 509 | + if(hcursor != NULL) | |
| 510 | + DestroyCursor(hcursor); | |
| 511 | + hcursor = nh; | |
| 512 | + } | |
| 513 | + unlock(&cursor.lk); | |
| 514 | + | |
| 515 | + free(and); | |
| 516 | + free(xor); | |
| 517 | + | |
| 518 | + PostMessage(window, WM_SETCURSOR, (int)window, 0); | |
| 519 | +} | |
| 520 | + | |
| 521 | +void | |
| 522 | +cursorarrow(void) | |
| 523 | +{ | |
| 524 | + if(hcursor != 0) { | |
| 525 | + DestroyCursor(hcursor); | |
| 526 | + hcursor = 0; | |
| 527 | + } | |
| 528 | + SetCursor(LoadCursor(0, IDC_ARROW)); | |
| 529 | + PostMessage(window, WM_SETCURSOR, (int)window, 0); | |
| 530 | +} | |
| 531 | + | |
| 532 | + | |
| 533 | +void | |
| 534 | +setcolor(ulong index, ulong red, ulong green, ulong blue) | |
| 535 | +{ | |
| 536 | +} | |
| 537 | + | |
| 538 | + | |
| 539 | +uchar* | |
| 540 | +clipreadunicode(HANDLE h) | |
| 541 | +{ | |
| 542 | + Rune *p; | |
| 543 | + int n; | |
| 544 | + uchar *q; | |
| 545 | + | |
| 546 | + p = GlobalLock(h); | |
| 547 | + n = wstrutflen(p)+1; | |
| 548 | + q = malloc(n); | |
| 549 | + wstrtoutf(q, p, n); | |
| 550 | + GlobalUnlock(h); | |
| 551 | + | |
| 552 | + return q; | |
| 553 | +} | |
| 554 | + | |
| 555 | +uchar * | |
| 556 | +clipreadutf(HANDLE h) | |
| 557 | +{ | |
| 558 | + uchar *p; | |
| 559 | + | |
| 560 | + p = GlobalLock(h); | |
| 561 | + p = strdup(p); | |
| 562 | + GlobalUnlock(h); | |
| 563 | + | |
| 564 | + return p; | |
| 565 | +} | |
| 566 | + | |
| 567 | + | |
| 568 | +uchar* | |
| 569 | +clipread() | |
| 570 | +{ | |
| 571 | + HANDLE h; | |
| 572 | + uchar *p; | |
| 573 | + | |
| 574 | + if(!OpenClipboard(window)) { | |
| 575 | + oserror(); | |
| 576 | + return strdup(""); | |
| 577 | + } | |
| 578 | + | |
| 579 | + if(h = GetClipboardData(CF_UNICODETEXT)) | |
| 580 | + p = clipreadunicode(h); | |
| 581 | + else if(h = GetClipboardData(CF_TEXT)) | |
| 582 | + p = clipreadutf(h); | |
| 583 | + else { | |
| 584 | + oserror(); | |
| 585 | + p = strdup(""); | |
| 586 | + } | |
| 587 | + | |
| 588 | + CloseClipboard(); | |
| 589 | + return p; | |
| 590 | +} | |
| 591 | + | |
| 592 | +int | |
| 593 | +clipwrite(char *buf) | |
| 594 | +{ | |
| 595 | + HANDLE h; | |
| 596 | + char *p, *e; | |
| 597 | + Rune *rp; | |
| 598 | + int n = strlen(buf); | |
| 599 | + | |
| 600 | + if(!OpenClipboard(window)) { | |
| 601 | + oserror(); | |
| 602 | + return -1; | |
| 603 | + } | |
| 604 | + | |
| 605 | + if(!EmptyClipboard()) { | |
| 606 | + oserror(); | |
| 607 | + CloseClipboard(); | |
| 608 | + return -1; | |
| 609 | + } | |
| 610 | + | |
| 611 | + h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune)); | |
| 612 | + if(h == NULL) | |
| 613 | + panic("out of memory"); | |
| 614 | + rp = GlobalLock(h); | |
| 615 | + p = buf; | |
| 616 | + e = p+n; | |
| 617 | + while(p<e) | |
| 618 | + p += chartorune(rp++, p); | |
| 619 | + *rp = 0; | |
| 620 | + GlobalUnlock(h); | |
| 621 | + | |
| 622 | + SetClipboardData(CF_UNICODETEXT, h); | |
| 623 | + | |
| 624 | + h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1); | |
| 625 | + if(h == NULL) | |
| 626 | + panic("out of memory"); | |
| 627 | + p = GlobalLock(h); | |
| 628 | + memcpy(p, buf, n); | |
| 629 | + p[n] = 0; | |
| 630 | + GlobalUnlock(h); | |
| 631 | + | |
| 632 | + SetClipboardData(CF_TEXT, h); | |
| 633 | + | |
| 634 | + CloseClipboard(); | |
| 635 | + return n; | |
| 636 | +} | |
| 637 | + | |
| 638 | +int | |
| 639 | +atlocalconsole(void) | |
| 640 | +{ | |
| 641 | + return 1; | |
| 642 | +} | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | + | |
| 4 | +int | |
| 5 | +wstrutflen(Rune *s) | |
| 6 | +{ | |
| 7 | + int n; | |
| 8 | + | |
| 9 | + for(n=0; *s; n+=runelen(*s),s++) | |
| 10 | + ; | |
| 11 | + return n; | |
| 12 | +} | |
| 13 | + | |
| 14 | +int | |
| 15 | +wstrtoutf(char *s, Rune *t, int n) | |
| 16 | +{ | |
| 17 | + int i; | |
| 18 | + char *s0; | |
| 19 | + | |
| 20 | + s0 = s; | |
| 21 | + if(n <= 0) | |
| 22 | + return wstrutflen(t)+1; | |
| 23 | + while(*t) { | |
| 24 | + if(n < UTFmax+1 && n < runelen(*t)+1) { | |
| 25 | + *s = 0; | |
| 26 | + return i+wstrutflen(t)+1; | |
| 27 | + } | |
| 28 | + i = runetochar(s, t); | |
| 29 | + s += i; | |
| 30 | + n -= i; | |
| 31 | + t++; | |
| 32 | + } | |
| 33 | + *s = 0; | |
| 34 | + return s-s0; | |
| 35 | +} | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +LIB=libx11.a | |
| 2 | +CC=gcc | |
| 3 | +CFLAGS=-I../include -I. -I/usr/X11R6/include -I../kern -c -ggdb -D_THREAD_SAFE -pthread | |
| 4 | +O=o | |
| 5 | + | |
| 6 | +OFILES=\ | |
| 7 | + alloc.$O\ | |
| 8 | + cload.$O\ | |
| 9 | + draw.$O\ | |
| 10 | + load.$O\ | |
| 11 | + screen.$O\ | |
| 12 | + keysym2ucs-x11.$O | |
| 13 | + | |
| 14 | +$(LIB): $(OFILES) | |
| 15 | + ar r $(LIB) $(OFILES) | |
| 16 | + ranlib $(LIB) | |
| 17 | + | |
| 18 | +%.$O: %.c | |
| 19 | + $(CC) $(CFLAGS) $*.c | |
| 20 | + | |
| @@ -0,0 +1,209 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | +#include "xmem.h" | |
| 6 | + | |
| 7 | +/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ | |
| 8 | +#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) | |
| 9 | + | |
| 10 | +Memimage* | |
| 11 | +xallocmemimage(Rectangle r, ulong chan, int pmid) | |
| 12 | +{ | |
| 13 | + Memimage *m; | |
| 14 | + Xmem *xm; | |
| 15 | + XImage *xi; | |
| 16 | + int offset; | |
| 17 | + int d; | |
| 18 | + | |
| 19 | + m = _allocmemimage(r, chan); | |
| 20 | + if(chan != GREY1 && chan != xscreenchan) | |
| 21 | + return m; | |
| 22 | + | |
| 23 | + d = m->depth; | |
| 24 | + xm = mallocz(sizeof(Xmem), 1); | |
| 25 | + if(pmid != PMundef) | |
| 26 | + xm->pmid = pmid; | |
| 27 | + else | |
| 28 | + xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d); | |
| 29 | + | |
| 30 | + if(m->depth == 24) | |
| 31 | + offset = r.min.x&(4-1); | |
| 32 | + else | |
| 33 | + offset = r.min.x&(31/m->depth); | |
| 34 | + r.min.x -= offset; | |
| 35 | + | |
| 36 | + assert(wordsperline(r, m->depth) <= m->width); | |
| 37 | + | |
| 38 | + xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0, | |
| 39 | + (char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(ulong)); | |
| 40 | + | |
| 41 | + if(xi == nil){ | |
| 42 | + _freememimage(m); | |
| 43 | + return nil; | |
| 44 | + } | |
| 45 | + | |
| 46 | + xm->xi = xi; | |
| 47 | + xm->pc = getcallerpc(&r); | |
| 48 | + xm->r = r; | |
| 49 | + | |
| 50 | + /* | |
| 51 | + * Set the parameters of the XImage so its memory looks exactly like a | |
| 52 | + * Memimage, so we can call _memimagedraw on the same data. All frame | |
| 53 | + * buffers we've seen, and Plan 9's graphics code, require big-endian | |
| 54 | + * bits within bytes, but little endian byte order within pixels. | |
| 55 | + */ | |
| 56 | + xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth; | |
| 57 | + xi->byte_order = LSBFirst; | |
| 58 | + xi->bitmap_bit_order = MSBFirst; | |
| 59 | + xi->bitmap_pad = 32; | |
| 60 | + xm->r = Rect(0,0,0,0); | |
| 61 | + XInitImage(xi); | |
| 62 | + XFlush(xdisplay); | |
| 63 | + | |
| 64 | + m->X = xm; | |
| 65 | + return m; | |
| 66 | +} | |
| 67 | + | |
| 68 | +Memimage* | |
| 69 | +allocmemimage(Rectangle r, ulong chan) | |
| 70 | +{ | |
| 71 | + return xallocmemimage(r, chan, PMundef); | |
| 72 | +} | |
| 73 | + | |
| 74 | +void | |
| 75 | +freememimage(Memimage *m) | |
| 76 | +{ | |
| 77 | + Xmem *xm; | |
| 78 | + | |
| 79 | + if(m == nil) | |
| 80 | + return; | |
| 81 | + | |
| 82 | + if(m->data->ref == 1){ | |
| 83 | + if((xm = m->X) != nil){ | |
| 84 | + if(xm->xi){ | |
| 85 | + xm->xi->data = nil; | |
| 86 | + XFree(xm->xi); | |
| 87 | + } | |
| 88 | + XFreePixmap(xdisplay, xm->pmid); | |
| 89 | + free(xm); | |
| 90 | + m->X = nil; | |
| 91 | + } | |
| 92 | + } | |
| 93 | + _freememimage(m); | |
| 94 | +} | |
| 95 | + | |
| 96 | +void | |
| 97 | +memfillcolor(Memimage *m, ulong val) | |
| 98 | +{ | |
| 99 | + _memfillcolor(m, val); | |
| 100 | + if(m->X){ | |
| 101 | + if((val & 0xFF) == 0xFF) | |
| 102 | + xfillcolor(m, m->r, _rgbatoimg(m, val)); | |
| 103 | + else | |
| 104 | + putXdata(m, m->r); | |
| 105 | + } | |
| 106 | +} | |
| 107 | + | |
| 108 | +static void | |
| 109 | +addrect(Rectangle *rp, Rectangle r) | |
| 110 | +{ | |
| 111 | + if(rp->min.x >= rp->max.x) | |
| 112 | + *rp = r; | |
| 113 | + else | |
| 114 | + combinerect(rp, r); | |
| 115 | +} | |
| 116 | + | |
| 117 | +XImage* | |
| 118 | +getXdata(Memimage *m, Rectangle r) | |
| 119 | +{ | |
| 120 | + uchar *p; | |
| 121 | + int x, y; | |
| 122 | + Xmem *xm; | |
| 123 | + Point xdelta, delta; | |
| 124 | + Point tp; | |
| 125 | + | |
| 126 | + xm = m->X; | |
| 127 | + if(xm == nil) | |
| 128 | + return; | |
| 129 | + | |
| 130 | + assert(xm != nil && xm->xi != nil); | |
| 131 | + | |
| 132 | + if(xm->dirty == 0) | |
| 133 | + return xm->xi; | |
| 134 | + | |
| 135 | + r = xm->dirtyr; | |
| 136 | + if(Dx(r)==0 || Dy(r)==0) | |
| 137 | + return xm->xi; | |
| 138 | + | |
| 139 | + delta = subpt(r.min, m->r.min); | |
| 140 | + tp = xm->r.min; /* avoid unaligned access on digital unix */ | |
| 141 | + xdelta = subpt(r.min, tp); | |
| 142 | + | |
| 143 | + XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r), | |
| 144 | + AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y); | |
| 145 | + | |
| 146 | + if(xtblbit && m->chan == CMAP8) | |
| 147 | + for(y=r.min.y; y<r.max.y; y++) | |
| 148 | + for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++) | |
| 149 | + *p = x11toplan9[*p]; | |
| 150 | + | |
| 151 | + xm->dirty = 0; | |
| 152 | + xm->dirtyr = Rect(0,0,0,0); | |
| 153 | + return xm->xi; | |
| 154 | +} | |
| 155 | + | |
| 156 | +void | |
| 157 | +putXdata(Memimage *m, Rectangle r) | |
| 158 | +{ | |
| 159 | + Xmem *xm; | |
| 160 | + XImage *xi; | |
| 161 | + GC g; | |
| 162 | + int offset; | |
| 163 | + Point xdelta, delta; | |
| 164 | + Point tp; | |
| 165 | + int x, y; | |
| 166 | + uchar *p; | |
| 167 | + | |
| 168 | + xm = m->X; | |
| 169 | + if(xm == nil) | |
| 170 | + return; | |
| 171 | + | |
| 172 | + assert(xm != nil); | |
| 173 | + assert(xm->xi != nil); | |
| 174 | + | |
| 175 | + xi = xm->xi; | |
| 176 | + | |
| 177 | + g = (m->chan == GREY1) ? xgccopy0 : xgccopy; | |
| 178 | + if(m->depth == 24) | |
| 179 | + offset = r.min.x % 4; | |
| 180 | + else | |
| 181 | + offset = m->r.min.x & (31/m->depth); | |
| 182 | + | |
| 183 | + delta = subpt(r.min, m->r.min); | |
| 184 | + tp = xm->r.min; /* avoid unaligned access on digital unix */ | |
| 185 | + xdelta = subpt(r.min, tp); | |
| 186 | + | |
| 187 | + if(xtblbit && m->chan == CMAP8) | |
| 188 | + for(y=r.min.y; y<r.max.y; y++) | |
| 189 | + for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++) | |
| 190 | + *p = plan9tox11[*p]; | |
| 191 | + | |
| 192 | + XPutImage(xdisplay, xm->pmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r)); | |
| 193 | + | |
| 194 | + if(xtblbit && m->chan == CMAP8) | |
| 195 | + for(y=r.min.y; y<r.max.y; y++) | |
| 196 | + for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++) | |
| 197 | + *p = x11toplan9[*p]; | |
| 198 | +} | |
| 199 | + | |
| 200 | +void | |
| 201 | +dirtyXdata(Memimage *m, Rectangle r) | |
| 202 | +{ | |
| 203 | + Xmem *xm; | |
| 204 | + | |
| 205 | + if((xm = m->X) != nil){ | |
| 206 | + xm->dirty = 1; | |
| 207 | + addrect(&xm->dirtyr, r); | |
| 208 | + } | |
| 209 | +} | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | +#include "xmem.h" | |
| 6 | + | |
| 7 | +int | |
| 8 | +cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) | |
| 9 | +{ | |
| 10 | + int n; | |
| 11 | + | |
| 12 | + n = _cloadmemimage(i, r, data, ndata); | |
| 13 | + if(n > 0 && i->X) | |
| 14 | + putXdata(i, r); | |
| 15 | + return n; | |
| 16 | +} | |
| @@ -0,0 +1,189 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | +#include "xmem.h" | |
| 6 | + | |
| 7 | +void xfillcolor(Memimage*, Rectangle, ulong); | |
| 8 | +static int xdraw(Memdrawparam*); | |
| 9 | + | |
| 10 | +int xgcfillcolor = 0; | |
| 11 | +int xgcfillcolor0 = 0; | |
| 12 | +int xgczeropm = 0; | |
| 13 | +int xgczeropm0 = 0; | |
| 14 | +int xgcsimplecolor = 0; | |
| 15 | +int xgcsimplecolor0 = 0; | |
| 16 | +int xgcsimplepm = 0; | |
| 17 | +int xgcsimplepm0 = 0; | |
| 18 | +int xgcreplsrctile = 0; | |
| 19 | +int xgcreplsrctile0 = 0; | |
| 20 | + | |
| 21 | +void | |
| 22 | +memimageinit(void) | |
| 23 | +{ | |
| 24 | + static int didinit = 0; | |
| 25 | + | |
| 26 | + if(didinit) | |
| 27 | + return; | |
| 28 | + | |
| 29 | + didinit = 1; | |
| 30 | + _memimageinit(); | |
| 31 | + | |
| 32 | + xfillcolor(memblack, memblack->r, 0); | |
| 33 | + xfillcolor(memwhite, memwhite->r, 1); | |
| 34 | +} | |
| 35 | + | |
| 36 | +void | |
| 37 | +memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) | |
| 38 | +{ | |
| 39 | + int didx; | |
| 40 | + Rectangle dr, mr, sr; | |
| 41 | + Memdrawparam *par; | |
| 42 | + | |
| 43 | + if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil) | |
| 44 | + return; | |
| 45 | + _memimagedraw(par); | |
| 46 | + if(!xdraw(par)) | |
| 47 | + putXdata(dst, par->r); | |
| 48 | +} | |
| 49 | + | |
| 50 | +void | |
| 51 | +xfillcolor(Memimage *m, Rectangle r, ulong v) | |
| 52 | +{ | |
| 53 | + GC gc; | |
| 54 | + Xmem *dxm; | |
| 55 | + | |
| 56 | + dxm = m->X; | |
| 57 | + assert(dxm != nil); | |
| 58 | + r = rectsubpt(r, m->r.min); | |
| 59 | + | |
| 60 | + if(m->chan == GREY1){ | |
| 61 | + gc = xgcfill0; | |
| 62 | + if(xgcfillcolor0 != v){ | |
| 63 | + XSetForeground(xdisplay, gc, v); | |
| 64 | + xgcfillcolor0 = v; | |
| 65 | + } | |
| 66 | + }else{ | |
| 67 | + if(m->chan == CMAP8 && xtblbit) | |
| 68 | + v = plan9tox11[v]; | |
| 69 | + | |
| 70 | + gc = xgcfill; | |
| 71 | + if(xgcfillcolor != v){ | |
| 72 | + XSetForeground(xdisplay, gc, v); | |
| 73 | + xgcfillcolor = v; | |
| 74 | + } | |
| 75 | + } | |
| 76 | + XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r)); | |
| 77 | +} | |
| 78 | + | |
| 79 | +static int | |
| 80 | +xdraw(Memdrawparam *par) | |
| 81 | +{ | |
| 82 | + int dy, dx; | |
| 83 | + unsigned m; | |
| 84 | + Memimage *src, *dst, *mask; | |
| 85 | + Xmem *dxm, *sxm, *mxm; | |
| 86 | + GC gc; | |
| 87 | + Rectangle r, sr, mr; | |
| 88 | + ulong sdval; | |
| 89 | + | |
| 90 | + dx = Dx(par->r); | |
| 91 | + dy = Dy(par->r); | |
| 92 | + src = par->src; | |
| 93 | + dst = par->dst; | |
| 94 | + mask = par->mask; | |
| 95 | + r = par->r; | |
| 96 | + sr = par->sr; | |
| 97 | + mr = par->mr; | |
| 98 | + sdval = par->sdval; | |
| 99 | + | |
| 100 | +return 0; | |
| 101 | + if((dxm = dst->X) == nil) | |
| 102 | + return 0; | |
| 103 | + | |
| 104 | + /* | |
| 105 | + * If we have an opaque mask and source is one opaque pixel we can convert to the | |
| 106 | + * destination format and just XFillRectangle. | |
| 107 | + */ | |
| 108 | + m = Simplesrc|Simplemask|Fullmask; | |
| 109 | + if((par->state&m)==m){ | |
| 110 | + xfillcolor(dst, r, sdval); | |
| 111 | + dirtyXdata(dst, par->r); | |
| 112 | + return 1; | |
| 113 | + } | |
| 114 | + | |
| 115 | + /* | |
| 116 | + * If no source alpha, an opaque mask, we can just copy the | |
| 117 | + * source onto the destination. If the channels are the same and | |
| 118 | + * the source is not replicated, XCopyArea suffices. | |
| 119 | + */ | |
| 120 | + m = Simplemask|Fullmask; | |
| 121 | + if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){ | |
| 122 | + sxm = src->X; | |
| 123 | + r = rectsubpt(r, dst->r.min); | |
| 124 | + sr = rectsubpt(sr, src->r.min); | |
| 125 | + if(dst->chan == GREY1) | |
| 126 | + gc = xgccopy0; | |
| 127 | + else | |
| 128 | + gc = xgccopy; | |
| 129 | + XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc, | |
| 130 | + sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y); | |
| 131 | + dirtyXdata(dst, par->r); | |
| 132 | + return 1; | |
| 133 | + } | |
| 134 | + | |
| 135 | + /* | |
| 136 | + * If no source alpha, a 1-bit mask, and a simple source | |
| 137 | + * we can just copy through the mask onto the destination. | |
| 138 | + */ | |
| 139 | + if(dst->X && mask->X && !(mask->flags&Frepl) | |
| 140 | + && mask->chan == GREY1 && (par->state&Simplesrc)){ | |
| 141 | + Point p; | |
| 142 | + | |
| 143 | + mxm = mask->X; | |
| 144 | + r = rectsubpt(r, dst->r.min); | |
| 145 | + mr = rectsubpt(mr, mask->r.min); | |
| 146 | + p = subpt(r.min, mr.min); | |
| 147 | + if(dst->chan == GREY1){ | |
| 148 | + gc = xgcsimplesrc0; | |
| 149 | + if(xgcsimplecolor0 != sdval){ | |
| 150 | + XSetForeground(xdisplay, gc, sdval); | |
| 151 | + xgcsimplecolor0 = sdval; | |
| 152 | + } | |
| 153 | + if(xgcsimplepm0 != mxm->pmid){ | |
| 154 | + XSetStipple(xdisplay, gc, mxm->pmid); | |
| 155 | + xgcsimplepm0 = mxm->pmid; | |
| 156 | + } | |
| 157 | + }else{ | |
| 158 | + /* somehow this doesn't work on rob's mac | |
| 159 | + gc = xgcsimplesrc; | |
| 160 | + if(dst->chan == CMAP8 && xtblbit) | |
| 161 | + sdval = plan9tox11[sdval]; | |
| 162 | + | |
| 163 | + if(xgcsimplecolor != sdval){ | |
| 164 | + XSetForeground(xdisplay, gc, sdval); | |
| 165 | + xgcsimplecolor = sdval; | |
| 166 | + } | |
| 167 | + if(xgcsimplepm != mxm->pmid){ | |
| 168 | + XSetStipple(xdisplay, gc, mxm->pmid); | |
| 169 | + xgcsimplepm = mxm->pmid; | |
| 170 | + } | |
| 171 | + */ | |
| 172 | + return 0; | |
| 173 | + } | |
| 174 | + XSetTSOrigin(xdisplay, gc, p.x, p.y); | |
| 175 | + XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy); | |
| 176 | + dirtyXdata(dst, par->r); | |
| 177 | + return 1; | |
| 178 | + } | |
| 179 | + return 0; | |
| 180 | +} | |
| 181 | + | |
| 182 | +ulong | |
| 183 | +pixelbits(Memimage *m, Point p) | |
| 184 | +{ | |
| 185 | + Xmem *xm; | |
| 186 | + if(m->X) | |
| 187 | + getXdata(m, Rect(p.x, p.y, p.x+1, p.y+1)); | |
| 188 | + return _pixelbits(m, p); | |
| 189 | +} | |
| @@ -0,0 +1,857 @@ | ||
| 1 | +/* $XFree86: xc/programs/xterm/keysym2ucs.c,v 1.5 2001/06/18 19:09:26 dickey Exp $ | |
| 2 | + * This module converts keysym values into the corresponding ISO 10646 | |
| 3 | + * (UCS, Unicode) values. | |
| 4 | + * | |
| 5 | + * The array keysymtab[] contains pairs of X11 keysym values for graphical | |
| 6 | + * characters and the corresponding Unicode value. The function | |
| 7 | + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, | |
| 8 | + * therefore keysymtab[] must remain SORTED by keysym value. | |
| 9 | + * | |
| 10 | + * The keysym -> UTF-8 conversion will hopefully one day be provided | |
| 11 | + * by Xlib via XmbLookupString() and should ideally not have to be | |
| 12 | + * done in X applications. But we are not there yet. | |
| 13 | + * | |
| 14 | + * We allow to represent any UCS character in the range U-00000000 to | |
| 15 | + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. | |
| 16 | + * This admittedly does not cover the entire 31-bit space of UCS, but | |
| 17 | + * it does cover all of the characters up to U-10FFFF, which can be | |
| 18 | + * represented by UTF-16, and more, and it is very unlikely that higher | |
| 19 | + * UCS codes will ever be assigned by ISO. So to get Unicode character | |
| 20 | + * U+ABCD you can directly use keysym 0x0100abcd. | |
| 21 | + * | |
| 22 | + * NOTE: The comments in the table below contain the actual character | |
| 23 | + * encoded in UTF-8, so for viewing and editing best use an editor in | |
| 24 | + * UTF-8 mode. | |
| 25 | + * | |
| 26 | + * Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001 | |
| 27 | + * | |
| 28 | + * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing | |
| 29 | + * an initial draft of the mapping table. | |
| 30 | + * | |
| 31 | + * This software is in the public domain. Share and enjoy! | |
| 32 | + * | |
| 33 | + * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl) | |
| 34 | + */ | |
| 35 | + | |
| 36 | +#ifndef KEYSYM2UCS_INCLUDED | |
| 37 | + | |
| 38 | +#include "keysym2ucs.h" | |
| 39 | +#define VISIBLE /* */ | |
| 40 | + | |
| 41 | +#else | |
| 42 | + | |
| 43 | +#define VISIBLE static | |
| 44 | + | |
| 45 | +#endif | |
| 46 | + | |
| 47 | +static struct codepair { | |
| 48 | + unsigned short keysym; | |
| 49 | + unsigned short ucs; | |
| 50 | +} keysymtab[] = { | |
| 51 | + { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */ | |
| 52 | + { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */ | |
| 53 | + { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */ | |
| 54 | + { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */ | |
| 55 | + { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */ | |
| 56 | + { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */ | |
| 57 | + { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */ | |
| 58 | + { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */ | |
| 59 | + { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */ | |
| 60 | + { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */ | |
| 61 | + { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */ | |
| 62 | + { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */ | |
| 63 | + { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */ | |
| 64 | + { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */ | |
| 65 | + { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */ | |
| 66 | + { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */ | |
| 67 | + { 0x01b7, 0x02c7 }, /* caron ˇ CARON */ | |
| 68 | + { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */ | |
| 69 | + { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */ | |
| 70 | + { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */ | |
| 71 | + { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */ | |
| 72 | + { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */ | |
| 73 | + { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */ | |
| 74 | + { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */ | |
| 75 | + { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */ | |
| 76 | + { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */ | |
| 77 | + { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */ | |
| 78 | + { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */ | |
| 79 | + { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */ | |
| 80 | + { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */ | |
| 81 | + { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */ | |
| 82 | + { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */ | |
| 83 | + { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */ | |
| 84 | + { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */ | |
| 85 | + { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */ | |
| 86 | + { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ | |
| 87 | + { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */ | |
| 88 | + { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */ | |
| 89 | + { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ | |
| 90 | + { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */ | |
| 91 | + { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */ | |
| 92 | + { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */ | |
| 93 | + { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */ | |
| 94 | + { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */ | |
| 95 | + { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */ | |
| 96 | + { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */ | |
| 97 | + { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */ | |
| 98 | + { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */ | |
| 99 | + { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */ | |
| 100 | + { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */ | |
| 101 | + { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */ | |
| 102 | + { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */ | |
| 103 | + { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */ | |
| 104 | + { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */ | |
| 105 | + { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */ | |
| 106 | + { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */ | |
| 107 | + { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */ | |
| 108 | + { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */ | |
| 109 | + { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ | |
| 110 | + { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */ | |
| 111 | + { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */ | |
| 112 | + { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ | |
| 113 | + { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */ | |
| 114 | + { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */ | |
| 115 | + { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */ | |
| 116 | + { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */ | |
| 117 | + { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */ | |
| 118 | + { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */ | |
| 119 | + { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ | |
| 120 | + { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */ | |
| 121 | + { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ | |
| 122 | + { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */ | |
| 123 | + { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ | |
| 124 | + { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */ | |
| 125 | + { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */ | |
| 126 | + { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */ | |
| 127 | + { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */ | |
| 128 | + { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */ | |
| 129 | + { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */ | |
| 130 | + { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */ | |
| 131 | + { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */ | |
| 132 | + { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */ | |
| 133 | + { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */ | |
| 134 | + { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */ | |
| 135 | + { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */ | |
| 136 | + { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */ | |
| 137 | + { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */ | |
| 138 | + { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */ | |
| 139 | + { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */ | |
| 140 | + { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */ | |
| 141 | + { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */ | |
| 142 | + { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */ | |
| 143 | + { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */ | |
| 144 | + { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */ | |
| 145 | + { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */ | |
| 146 | + { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */ | |
| 147 | + { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */ | |
| 148 | + { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */ | |
| 149 | + { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */ | |
| 150 | + { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */ | |
| 151 | + { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */ | |
| 152 | + { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */ | |
| 153 | + { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */ | |
| 154 | + { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */ | |
| 155 | + { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */ | |
| 156 | + { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */ | |
| 157 | + { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */ | |
| 158 | + { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */ | |
| 159 | + { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */ | |
| 160 | + { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */ | |
| 161 | + { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */ | |
| 162 | + { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */ | |
| 163 | + { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */ | |
| 164 | + { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */ | |
| 165 | + { 0x047e, 0x203e }, /* overline ‾ OVERLINE */ | |
| 166 | + { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */ | |
| 167 | + { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */ | |
| 168 | + { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */ | |
| 169 | + { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */ | |
| 170 | + { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */ | |
| 171 | + { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */ | |
| 172 | + { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */ | |
| 173 | + { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */ | |
| 174 | + { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */ | |
| 175 | + { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */ | |
| 176 | + { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */ | |
| 177 | + { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */ | |
| 178 | + { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */ | |
| 179 | + { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */ | |
| 180 | + { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */ | |
| 181 | + { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */ | |
| 182 | + { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */ | |
| 183 | + { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */ | |
| 184 | + { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */ | |
| 185 | + { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */ | |
| 186 | + { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */ | |
| 187 | + { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */ | |
| 188 | + { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */ | |
| 189 | + { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */ | |
| 190 | + { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */ | |
| 191 | + { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */ | |
| 192 | + { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */ | |
| 193 | + { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */ | |
| 194 | + { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */ | |
| 195 | + { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */ | |
| 196 | + { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */ | |
| 197 | + { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */ | |
| 198 | + { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */ | |
| 199 | + { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */ | |
| 200 | + { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */ | |
| 201 | + { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */ | |
| 202 | + { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */ | |
| 203 | + { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */ | |
| 204 | + { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */ | |
| 205 | + { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */ | |
| 206 | + { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */ | |
| 207 | + { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */ | |
| 208 | + { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */ | |
| 209 | + { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */ | |
| 210 | + { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */ | |
| 211 | + { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */ | |
| 212 | + { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */ | |
| 213 | + { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */ | |
| 214 | + { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */ | |
| 215 | + { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */ | |
| 216 | + { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */ | |
| 217 | + { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */ | |
| 218 | + { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */ | |
| 219 | + { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */ | |
| 220 | + { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */ | |
| 221 | + { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */ | |
| 222 | + { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */ | |
| 223 | + { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */ | |
| 224 | + { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */ | |
| 225 | + { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */ | |
| 226 | + { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */ | |
| 227 | + { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */ | |
| 228 | + { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ | |
| 229 | + { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */ | |
| 230 | + { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */ | |
| 231 | + { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */ | |
| 232 | + { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */ | |
| 233 | + { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */ | |
| 234 | + { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */ | |
| 235 | + { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */ | |
| 236 | + { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */ | |
| 237 | + { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */ | |
| 238 | + { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */ | |
| 239 | + { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */ | |
| 240 | + { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */ | |
| 241 | + { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */ | |
| 242 | + { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */ | |
| 243 | + { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */ | |
| 244 | + { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */ | |
| 245 | + { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */ | |
| 246 | + { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */ | |
| 247 | + { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */ | |
| 248 | + { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */ | |
| 249 | + { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */ | |
| 250 | + { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */ | |
| 251 | + { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */ | |
| 252 | + { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */ | |
| 253 | + { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */ | |
| 254 | + { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */ | |
| 255 | + { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */ | |
| 256 | + { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */ | |
| 257 | + { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */ | |
| 258 | + { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */ | |
| 259 | + { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */ | |
| 260 | + { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */ | |
| 261 | + { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */ | |
| 262 | + { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */ | |
| 263 | + { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */ | |
| 264 | + { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */ | |
| 265 | + { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */ | |
| 266 | + { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */ | |
| 267 | + { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */ | |
| 268 | + { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */ | |
| 269 | + { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */ | |
| 270 | + { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */ | |
| 271 | + { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */ | |
| 272 | + { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */ | |
| 273 | + { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */ | |
| 274 | + { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */ | |
| 275 | + { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */ | |
| 276 | + { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */ | |
| 277 | + { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */ | |
| 278 | + { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */ | |
| 279 | + { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */ | |
| 280 | + { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */ | |
| 281 | + { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */ | |
| 282 | + { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ | |
| 283 | + { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */ | |
| 284 | + { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */ | |
| 285 | + { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */ | |
| 286 | + { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */ | |
| 287 | + { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */ | |
| 288 | + { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */ | |
| 289 | + { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */ | |
| 290 | + { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */ | |
| 291 | + { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */ | |
| 292 | + { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */ | |
| 293 | + { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */ | |
| 294 | + { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */ | |
| 295 | + { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */ | |
| 296 | + { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */ | |
| 297 | + { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ | |
| 298 | + { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */ | |
| 299 | + { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */ | |
| 300 | + { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */ | |
| 301 | + { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */ | |
| 302 | + { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */ | |
| 303 | + { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */ | |
| 304 | + { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */ | |
| 305 | + { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */ | |
| 306 | + { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */ | |
| 307 | + { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */ | |
| 308 | + { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */ | |
| 309 | + { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */ | |
| 310 | + { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */ | |
| 311 | + { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */ | |
| 312 | + { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */ | |
| 313 | + { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */ | |
| 314 | + { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */ | |
| 315 | + { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */ | |
| 316 | + { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */ | |
| 317 | + { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */ | |
| 318 | + { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */ | |
| 319 | + { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */ | |
| 320 | + { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */ | |
| 321 | + { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */ | |
| 322 | + { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */ | |
| 323 | + { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */ | |
| 324 | + { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */ | |
| 325 | + { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */ | |
| 326 | + { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */ | |
| 327 | + { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */ | |
| 328 | + { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */ | |
| 329 | + { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */ | |
| 330 | + { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */ | |
| 331 | + { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */ | |
| 332 | + { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */ | |
| 333 | + { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */ | |
| 334 | + { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */ | |
| 335 | + { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */ | |
| 336 | + { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */ | |
| 337 | + { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */ | |
| 338 | + { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */ | |
| 339 | + { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */ | |
| 340 | + { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */ | |
| 341 | + { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */ | |
| 342 | + { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */ | |
| 343 | + { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */ | |
| 344 | + { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */ | |
| 345 | + { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */ | |
| 346 | + { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */ | |
| 347 | + { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */ | |
| 348 | + { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */ | |
| 349 | + { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */ | |
| 350 | + { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */ | |
| 351 | + { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */ | |
| 352 | + { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */ | |
| 353 | + { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */ | |
| 354 | + { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */ | |
| 355 | + { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */ | |
| 356 | + { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */ | |
| 357 | + { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */ | |
| 358 | + { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */ | |
| 359 | + { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */ | |
| 360 | + { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */ | |
| 361 | + { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */ | |
| 362 | + { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */ | |
| 363 | + { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */ | |
| 364 | + { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */ | |
| 365 | + { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */ | |
| 366 | + { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */ | |
| 367 | + { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */ | |
| 368 | + { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */ | |
| 369 | + { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */ | |
| 370 | + { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */ | |
| 371 | + { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */ | |
| 372 | + { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */ | |
| 373 | + { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */ | |
| 374 | + { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ | |
| 375 | + { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */ | |
| 376 | + { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */ | |
| 377 | + { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ | |
| 378 | + { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */ | |
| 379 | + { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */ | |
| 380 | + { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */ | |
| 381 | + { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */ | |
| 382 | + { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */ | |
| 383 | + { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */ | |
| 384 | + { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */ | |
| 385 | + { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */ | |
| 386 | + { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ | |
| 387 | + { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */ | |
| 388 | + { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */ | |
| 389 | + { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ | |
| 390 | + { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ | |
| 391 | + { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */ | |
| 392 | + { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */ | |
| 393 | + { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */ | |
| 394 | + { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */ | |
| 395 | + { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */ | |
| 396 | + { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */ | |
| 397 | + { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */ | |
| 398 | + { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */ | |
| 399 | + { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */ | |
| 400 | + { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */ | |
| 401 | + { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */ | |
| 402 | + { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */ | |
| 403 | + { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */ | |
| 404 | + { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */ | |
| 405 | + { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */ | |
| 406 | + { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */ | |
| 407 | + { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */ | |
| 408 | + { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */ | |
| 409 | + { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */ | |
| 410 | + { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */ | |
| 411 | + { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */ | |
| 412 | + { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */ | |
| 413 | + { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */ | |
| 414 | + { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */ | |
| 415 | + { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */ | |
| 416 | + { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */ | |
| 417 | + { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */ | |
| 418 | + { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */ | |
| 419 | + { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */ | |
| 420 | + { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */ | |
| 421 | + { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */ | |
| 422 | + { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */ | |
| 423 | + { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */ | |
| 424 | + { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */ | |
| 425 | + { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */ | |
| 426 | + { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */ | |
| 427 | + { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */ | |
| 428 | + { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */ | |
| 429 | + { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */ | |
| 430 | + { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */ | |
| 431 | + { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */ | |
| 432 | + { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */ | |
| 433 | + { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */ | |
| 434 | + { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */ | |
| 435 | + { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */ | |
| 436 | + { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */ | |
| 437 | + { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */ | |
| 438 | + { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */ | |
| 439 | + { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */ | |
| 440 | + { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */ | |
| 441 | + { 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */ | |
| 442 | + { 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ | |
| 443 | + { 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */ | |
| 444 | + { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */ | |
| 445 | + { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */ | |
| 446 | + { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */ | |
| 447 | + { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */ | |
| 448 | + { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */ | |
| 449 | + { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */ | |
| 450 | + { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */ | |
| 451 | + { 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */ | |
| 452 | + { 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */ | |
| 453 | + { 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */ | |
| 454 | + { 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */ | |
| 455 | + { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */ | |
| 456 | + { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */ | |
| 457 | +/* 0x08b1 topleftsummation ? ??? */ | |
| 458 | +/* 0x08b2 botleftsummation ? ??? */ | |
| 459 | +/* 0x08b3 topvertsummationconnector ? ??? */ | |
| 460 | +/* 0x08b4 botvertsummationconnector ? ??? */ | |
| 461 | +/* 0x08b5 toprightsummation ? ??? */ | |
| 462 | +/* 0x08b6 botrightsummation ? ??? */ | |
| 463 | +/* 0x08b7 rightmiddlesummation ? ??? */ | |
| 464 | + { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */ | |
| 465 | + { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */ | |
| 466 | + { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */ | |
| 467 | + { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */ | |
| 468 | + { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */ | |
| 469 | + { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */ | |
| 470 | + { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */ | |
| 471 | + { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */ | |
| 472 | + { 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */ | |
| 473 | + { 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */ | |
| 474 | + { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */ | |
| 475 | + { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */ | |
| 476 | + { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */ | |
| 477 | + { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */ | |
| 478 | + { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */ | |
| 479 | + { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */ | |
| 480 | + { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */ | |
| 481 | + { 0x08dd, 0x222a }, /* union ∪ UNION */ | |
| 482 | + { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */ | |
| 483 | + { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */ | |
| 484 | + { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */ | |
| 485 | + { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */ | |
| 486 | + { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */ | |
| 487 | + { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */ | |
| 488 | + { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */ | |
| 489 | + { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */ | |
| 490 | +/* 0x09df blank ? ??? */ | |
| 491 | + { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */ | |
| 492 | + { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */ | |
| 493 | + { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */ | |
| 494 | + { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */ | |
| 495 | + { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */ | |
| 496 | + { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */ | |
| 497 | + { 0x09e8, 0x2424 }, /* nl  SYMBOL FOR NEWLINE */ | |
| 498 | + { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */ | |
| 499 | + { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */ | |
| 500 | + { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */ | |
| 501 | + { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */ | |
| 502 | + { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */ | |
| 503 | + { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ | |
| 504 | + { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ | |
| 505 | + { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ | |
| 506 | + { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */ | |
| 507 | + { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ | |
| 508 | + { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ | |
| 509 | + { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ | |
| 510 | + { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */ | |
| 511 | + { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */ | |
| 512 | + { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ | |
| 513 | + { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */ | |
| 514 | + { 0x0aa1, 0x2003 }, /* emspace EM SPACE */ | |
| 515 | + { 0x0aa2, 0x2002 }, /* enspace EN SPACE */ | |
| 516 | + { 0x0aa3, 0x2004 }, /* em3space THREE-PER-EM SPACE */ | |
| 517 | + { 0x0aa4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */ | |
| 518 | + { 0x0aa5, 0x2007 }, /* digitspace FIGURE SPACE */ | |
| 519 | + { 0x0aa6, 0x2008 }, /* punctspace PUNCTUATION SPACE */ | |
| 520 | + { 0x0aa7, 0x2009 }, /* thinspace THIN SPACE */ | |
| 521 | + { 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */ | |
| 522 | + { 0x0aa9, 0x2014 }, /* emdash — EM DASH */ | |
| 523 | + { 0x0aaa, 0x2013 }, /* endash – EN DASH */ | |
| 524 | +/* 0x0aac signifblank ? ??? */ | |
| 525 | + { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */ | |
| 526 | + { 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */ | |
| 527 | + { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */ | |
| 528 | + { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */ | |
| 529 | + { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */ | |
| 530 | + { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */ | |
| 531 | + { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */ | |
| 532 | + { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */ | |
| 533 | + { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */ | |
| 534 | + { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */ | |
| 535 | + { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */ | |
| 536 | + { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */ | |
| 537 | + { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */ | |
| 538 | +/* 0x0abd decimalpoint ? ??? */ | |
| 539 | + { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */ | |
| 540 | +/* 0x0abf marker ? ??? */ | |
| 541 | + { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */ | |
| 542 | + { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */ | |
| 543 | + { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */ | |
| 544 | + { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */ | |
| 545 | + { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */ | |
| 546 | + { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */ | |
| 547 | +/* 0x0acb trademarkincircle ? ??? */ | |
| 548 | + { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */ | |
| 549 | + { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */ | |
| 550 | + { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */ | |
| 551 | + { 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */ | |
| 552 | + { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */ | |
| 553 | + { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */ | |
| 554 | + { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */ | |
| 555 | + { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */ | |
| 556 | + { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */ | |
| 557 | + { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */ | |
| 558 | + { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */ | |
| 559 | + { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */ | |
| 560 | +/* 0x0ada hexagram ? ??? */ | |
| 561 | + { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */ | |
| 562 | + { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */ | |
| 563 | + { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */ | |
| 564 | + { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */ | |
| 565 | + { 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */ | |
| 566 | + { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */ | |
| 567 | + { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */ | |
| 568 | + { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */ | |
| 569 | + { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */ | |
| 570 | + { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */ | |
| 571 | + { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */ | |
| 572 | + { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */ | |
| 573 | + { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */ | |
| 574 | + { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */ | |
| 575 | + { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */ | |
| 576 | + { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */ | |
| 577 | + { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */ | |
| 578 | + { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */ | |
| 579 | + { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */ | |
| 580 | + { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */ | |
| 581 | + { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */ | |
| 582 | + { 0x0af1, 0x2020 }, /* dagger † DAGGER */ | |
| 583 | + { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */ | |
| 584 | + { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */ | |
| 585 | + { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */ | |
| 586 | + { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */ | |
| 587 | + { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */ | |
| 588 | + { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */ | |
| 589 | + { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */ | |
| 590 | + { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */ | |
| 591 | + { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */ | |
| 592 | + { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */ | |
| 593 | + { 0x0afc, 0x2038 }, /* caret ‸ CARET */ | |
| 594 | + { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */ | |
| 595 | + { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */ | |
| 596 | +/* 0x0aff cursor ? ??? */ | |
| 597 | + { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */ | |
| 598 | + { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */ | |
| 599 | + { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */ | |
| 600 | + { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */ | |
| 601 | + { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */ | |
| 602 | + { 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */ | |
| 603 | + { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */ | |
| 604 | + { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */ | |
| 605 | + { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */ | |
| 606 | + { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */ | |
| 607 | + { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */ | |
| 608 | + { 0x0bce, 0x22a4 }, /* uptack ⊤ DOWN TACK */ | |
| 609 | + { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */ | |
| 610 | + { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */ | |
| 611 | + { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */ | |
| 612 | + { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */ | |
| 613 | + { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */ | |
| 614 | + { 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */ | |
| 615 | + { 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */ | |
| 616 | + { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */ | |
| 617 | + { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */ | |
| 618 | + { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */ | |
| 619 | + { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */ | |
| 620 | + { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */ | |
| 621 | + { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */ | |
| 622 | + { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */ | |
| 623 | + { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */ | |
| 624 | + { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */ | |
| 625 | + { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */ | |
| 626 | + { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */ | |
| 627 | + { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */ | |
| 628 | + { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */ | |
| 629 | + { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */ | |
| 630 | + { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */ | |
| 631 | + { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */ | |
| 632 | + { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */ | |
| 633 | + { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */ | |
| 634 | + { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */ | |
| 635 | + { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */ | |
| 636 | + { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */ | |
| 637 | + { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */ | |
| 638 | + { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */ | |
| 639 | + { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */ | |
| 640 | + { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */ | |
| 641 | + { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */ | |
| 642 | + { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */ | |
| 643 | + { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */ | |
| 644 | + { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */ | |
| 645 | + { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */ | |
| 646 | + { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */ | |
| 647 | + { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */ | |
| 648 | + { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */ | |
| 649 | + { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */ | |
| 650 | + { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */ | |
| 651 | + { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */ | |
| 652 | + { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */ | |
| 653 | + { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */ | |
| 654 | + { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */ | |
| 655 | + { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */ | |
| 656 | + { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */ | |
| 657 | + { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */ | |
| 658 | + { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */ | |
| 659 | + { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */ | |
| 660 | + { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */ | |
| 661 | + { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */ | |
| 662 | + { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */ | |
| 663 | + { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */ | |
| 664 | + { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */ | |
| 665 | + { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */ | |
| 666 | + { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */ | |
| 667 | + { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */ | |
| 668 | + { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */ | |
| 669 | + { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */ | |
| 670 | + { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */ | |
| 671 | + { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */ | |
| 672 | + { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */ | |
| 673 | + { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */ | |
| 674 | + { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */ | |
| 675 | + { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */ | |
| 676 | + { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */ | |
| 677 | + { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */ | |
| 678 | + { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */ | |
| 679 | + { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */ | |
| 680 | + { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */ | |
| 681 | + { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */ | |
| 682 | + { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */ | |
| 683 | + { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */ | |
| 684 | + { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */ | |
| 685 | + { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */ | |
| 686 | + { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */ | |
| 687 | + { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */ | |
| 688 | + { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */ | |
| 689 | + { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */ | |
| 690 | + { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */ | |
| 691 | + { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */ | |
| 692 | + { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */ | |
| 693 | + { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */ | |
| 694 | + { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */ | |
| 695 | + { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */ | |
| 696 | + { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */ | |
| 697 | + { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */ | |
| 698 | + { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */ | |
| 699 | + { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */ | |
| 700 | + { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */ | |
| 701 | + { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */ | |
| 702 | +/* 0x0dde Thai_maihanakat_maitho ? ??? */ | |
| 703 | + { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */ | |
| 704 | + { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */ | |
| 705 | + { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */ | |
| 706 | + { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */ | |
| 707 | + { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */ | |
| 708 | + { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */ | |
| 709 | + { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */ | |
| 710 | + { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */ | |
| 711 | + { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */ | |
| 712 | + { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */ | |
| 713 | + { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */ | |
| 714 | + { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */ | |
| 715 | + { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */ | |
| 716 | + { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */ | |
| 717 | + { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */ | |
| 718 | + { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */ | |
| 719 | + { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */ | |
| 720 | + { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */ | |
| 721 | + { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */ | |
| 722 | + { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */ | |
| 723 | + { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */ | |
| 724 | + { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */ | |
| 725 | + { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */ | |
| 726 | + { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */ | |
| 727 | + { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */ | |
| 728 | + { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */ | |
| 729 | + { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */ | |
| 730 | + { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */ | |
| 731 | + { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */ | |
| 732 | + { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */ | |
| 733 | + { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */ | |
| 734 | + { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */ | |
| 735 | + { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */ | |
| 736 | + { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */ | |
| 737 | + { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */ | |
| 738 | + { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */ | |
| 739 | + { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */ | |
| 740 | + { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */ | |
| 741 | + { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */ | |
| 742 | + { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */ | |
| 743 | + { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */ | |
| 744 | + { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */ | |
| 745 | + { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */ | |
| 746 | + { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */ | |
| 747 | + { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */ | |
| 748 | + { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */ | |
| 749 | + { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */ | |
| 750 | + { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */ | |
| 751 | + { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */ | |
| 752 | + { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */ | |
| 753 | + { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */ | |
| 754 | + { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */ | |
| 755 | + { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */ | |
| 756 | + { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */ | |
| 757 | + { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */ | |
| 758 | + { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */ | |
| 759 | + { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */ | |
| 760 | + { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */ | |
| 761 | + { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */ | |
| 762 | + { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */ | |
| 763 | + { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */ | |
| 764 | + { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */ | |
| 765 | + { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */ | |
| 766 | + { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */ | |
| 767 | + { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */ | |
| 768 | + { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */ | |
| 769 | + { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */ | |
| 770 | + { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */ | |
| 771 | + { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */ | |
| 772 | + { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */ | |
| 773 | + { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */ | |
| 774 | + { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */ | |
| 775 | + { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */ | |
| 776 | + { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */ | |
| 777 | + { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */ | |
| 778 | + { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */ | |
| 779 | + { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */ | |
| 780 | + { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */ | |
| 781 | + { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */ | |
| 782 | + { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */ | |
| 783 | + { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */ | |
| 784 | + { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */ | |
| 785 | + { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */ | |
| 786 | + { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */ | |
| 787 | + { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */ | |
| 788 | + { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */ | |
| 789 | + { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */ | |
| 790 | + { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */ | |
| 791 | + { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */ | |
| 792 | + { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */ | |
| 793 | + { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */ | |
| 794 | + { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */ | |
| 795 | + { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */ | |
| 796 | + { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */ | |
| 797 | + { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */ | |
| 798 | + { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */ | |
| 799 | + { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */ | |
| 800 | + { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */ | |
| 801 | + { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */ | |
| 802 | + { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */ | |
| 803 | + { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */ | |
| 804 | + { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */ | |
| 805 | + { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */ | |
| 806 | + { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */ | |
| 807 | + { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */ | |
| 808 | + { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */ | |
| 809 | + { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */ | |
| 810 | + { 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */ | |
| 811 | + { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */ | |
| 812 | + { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */ | |
| 813 | + { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */ | |
| 814 | + { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */ | |
| 815 | + { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */ | |
| 816 | + { 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */ | |
| 817 | + { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */ | |
| 818 | + { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */ | |
| 819 | + { 0x13a4, 0x20ac }, /* Euro € EURO SIGN */ | |
| 820 | + { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */ | |
| 821 | + { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */ | |
| 822 | + { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */ | |
| 823 | + { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */ | |
| 824 | +}; | |
| 825 | + | |
| 826 | +VISIBLE | |
| 827 | +long keysym2ucs(KeySym keysym) | |
| 828 | +{ | |
| 829 | + int min = 0; | |
| 830 | + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; | |
| 831 | + int mid; | |
| 832 | + | |
| 833 | + /* first check for Latin-1 characters (1:1 mapping) */ | |
| 834 | + if ((keysym >= 0x0020 && keysym <= 0x007e) || | |
| 835 | + (keysym >= 0x00a0 && keysym <= 0x00ff)) | |
| 836 | + return keysym; | |
| 837 | + | |
| 838 | + /* also check for directly encoded 24-bit UCS characters */ | |
| 839 | + if ((keysym & 0xff000000) == 0x01000000) | |
| 840 | + return keysym & 0x00ffffff; | |
| 841 | + | |
| 842 | + /* binary search in table */ | |
| 843 | + while (max >= min) { | |
| 844 | + mid = (min + max) / 2; | |
| 845 | + if (keysymtab[mid].keysym < keysym) | |
| 846 | + min = mid + 1; | |
| 847 | + else if (keysymtab[mid].keysym > keysym) | |
| 848 | + max = mid - 1; | |
| 849 | + else { | |
| 850 | + /* found it */ | |
| 851 | + return keysymtab[mid].ucs; | |
| 852 | + } | |
| 853 | + } | |
| 854 | + | |
| 855 | + /* no matching Unicode value found */ | |
| 856 | + return -1; | |
| 857 | +} | |
| @@ -0,0 +1,9 @@ | ||
| 1 | +/* $XFree86: xc/programs/xterm/keysym2ucs.h,v 1.1 1999/06/12 15:37:18 dawes Exp $ */ | |
| 2 | +/* | |
| 3 | + * This module converts keysym values into the corresponding ISO 10646-1 | |
| 4 | + * (UCS, Unicode) values. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <X11/X.h> | |
| 8 | + | |
| 9 | +long keysym2ucs(KeySym keysym); | |
| @@ -0,0 +1,754 @@ | ||
| 1 | +static ulong | |
| 2 | +ksym2utf[] = { | |
| 3 | + [0x01a1] 0x0104, | |
| 4 | + [0x01a2] 0x02d8, | |
| 5 | + [0x01a3] 0x0141, | |
| 6 | + [0x01a5] 0x013d, | |
| 7 | + [0x01a6] 0x015a, | |
| 8 | + [0x01a9] 0x0160, | |
| 9 | + [0x01aa] 0x015e, | |
| 10 | + [0x01ab] 0x0164, | |
| 11 | + [0x01ac] 0x0179, | |
| 12 | + [0x01ae] 0x017d, | |
| 13 | + [0x01af] 0x017b, | |
| 14 | + [0x01b1] 0x0105, | |
| 15 | + [0x01b2] 0x02db, | |
| 16 | + [0x01b3] 0x0142, | |
| 17 | + [0x01b5] 0x013e, | |
| 18 | + [0x01b6] 0x015b, | |
| 19 | + [0x01b7] 0x02c7, | |
| 20 | + [0x01b9] 0x0161, | |
| 21 | + [0x01ba] 0x015f, | |
| 22 | + [0x01bb] 0x0165, | |
| 23 | + [0x01bc] 0x017a, | |
| 24 | + [0x01bd] 0x02dd, | |
| 25 | + [0x01be] 0x017e, | |
| 26 | + [0x01bf] 0x017c, | |
| 27 | + [0x01c0] 0x0154, | |
| 28 | + [0x01c3] 0x0102, | |
| 29 | + [0x01c5] 0x0139, | |
| 30 | + [0x01c6] 0x0106, | |
| 31 | + [0x01c8] 0x010c, | |
| 32 | + [0x01ca] 0x0118, | |
| 33 | + [0x01cc] 0x011a, | |
| 34 | + [0x01cf] 0x010e, | |
| 35 | + [0x01d0] 0x0110, | |
| 36 | + [0x01d1] 0x0143, | |
| 37 | + [0x01d2] 0x0147, | |
| 38 | + [0x01d5] 0x0150, | |
| 39 | + [0x01d8] 0x0158, | |
| 40 | + [0x01d9] 0x016e, | |
| 41 | + [0x01db] 0x0170, | |
| 42 | + [0x01de] 0x0162, | |
| 43 | + [0x01e0] 0x0155, | |
| 44 | + [0x01e3] 0x0103, | |
| 45 | + [0x01e5] 0x013a, | |
| 46 | + [0x01e6] 0x0107, | |
| 47 | + [0x01e8] 0x010d, | |
| 48 | + [0x01ea] 0x0119, | |
| 49 | + [0x01ec] 0x011b, | |
| 50 | + [0x01ef] 0x010f, | |
| 51 | + [0x01f0] 0x0111, | |
| 52 | + [0x01f1] 0x0144, | |
| 53 | + [0x01f2] 0x0148, | |
| 54 | + [0x01f5] 0x0151, | |
| 55 | + [0x01f8] 0x0159, | |
| 56 | + [0x01f9] 0x016f, | |
| 57 | + [0x01fb] 0x0171, | |
| 58 | + [0x01fe] 0x0163, | |
| 59 | + [0x01ff] 0x02d9, | |
| 60 | + [0x02a1] 0x0126, | |
| 61 | + [0x02a6] 0x0124, | |
| 62 | + [0x02a9] 0x0130, | |
| 63 | + [0x02ab] 0x011e, | |
| 64 | + [0x02ac] 0x0134, | |
| 65 | + [0x02b1] 0x0127, | |
| 66 | + [0x02b6] 0x0125, | |
| 67 | + [0x02b9] 0x0131, | |
| 68 | + [0x02bb] 0x011f, | |
| 69 | + [0x02bc] 0x0135, | |
| 70 | + [0x02c5] 0x010a, | |
| 71 | + [0x02c6] 0x0108, | |
| 72 | + [0x02d5] 0x0120, | |
| 73 | + [0x02d8] 0x011c, | |
| 74 | + [0x02dd] 0x016c, | |
| 75 | + [0x02de] 0x015c, | |
| 76 | + [0x02e5] 0x010b, | |
| 77 | + [0x02e6] 0x0109, | |
| 78 | + [0x02f5] 0x0121, | |
| 79 | + [0x02f8] 0x011d, | |
| 80 | + [0x02fd] 0x016d, | |
| 81 | + [0x02fe] 0x015d, | |
| 82 | + [0x03a2] 0x0138, | |
| 83 | + [0x03a3] 0x0156, | |
| 84 | + [0x03a5] 0x0128, | |
| 85 | + [0x03a6] 0x013b, | |
| 86 | + [0x03aa] 0x0112, | |
| 87 | + [0x03ab] 0x0122, | |
| 88 | + [0x03ac] 0x0166, | |
| 89 | + [0x03b3] 0x0157, | |
| 90 | + [0x03b5] 0x0129, | |
| 91 | + [0x03b6] 0x013c, | |
| 92 | + [0x03ba] 0x0113, | |
| 93 | + [0x03bb] 0x0123, | |
| 94 | + [0x03bc] 0x0167, | |
| 95 | + [0x03bd] 0x014a, | |
| 96 | + [0x03bf] 0x014b, | |
| 97 | + [0x03c0] 0x0100, | |
| 98 | + [0x03c7] 0x012e, | |
| 99 | + [0x03cc] 0x0116, | |
| 100 | + [0x03cf] 0x012a, | |
| 101 | + [0x03d1] 0x0145, | |
| 102 | + [0x03d2] 0x014c, | |
| 103 | + [0x03d3] 0x0136, | |
| 104 | + [0x03d9] 0x0172, | |
| 105 | + [0x03dd] 0x0168, | |
| 106 | + [0x03de] 0x016a, | |
| 107 | + [0x03e0] 0x0101, | |
| 108 | + [0x03e7] 0x012f, | |
| 109 | + [0x03ec] 0x0117, | |
| 110 | + [0x03ef] 0x012b, | |
| 111 | + [0x03f1] 0x0146, | |
| 112 | + [0x03f2] 0x014d, | |
| 113 | + [0x03f3] 0x0137, | |
| 114 | + [0x03f9] 0x0173, | |
| 115 | + [0x03fd] 0x0169, | |
| 116 | + [0x03fe] 0x016b, | |
| 117 | + [0x047e] 0x203e, | |
| 118 | + [0x04a1] 0x3002, | |
| 119 | + [0x04a2] 0x300c, | |
| 120 | + [0x04a3] 0x300d, | |
| 121 | + [0x04a4] 0x3001, | |
| 122 | + [0x04a5] 0x30fb, | |
| 123 | + [0x04a6] 0x30f2, | |
| 124 | + [0x04a7] 0x30a1, | |
| 125 | + [0x04a8] 0x30a3, | |
| 126 | + [0x04a9] 0x30a5, | |
| 127 | + [0x04aa] 0x30a7, | |
| 128 | + [0x04ab] 0x30a9, | |
| 129 | + [0x04ac] 0x30e3, | |
| 130 | + [0x04ad] 0x30e5, | |
| 131 | + [0x04ae] 0x30e7, | |
| 132 | + [0x04af] 0x30c3, | |
| 133 | + [0x04b0] 0x30fc, | |
| 134 | + [0x04b1] 0x30a2, | |
| 135 | + [0x04b2] 0x30a4, | |
| 136 | + [0x04b3] 0x30a6, | |
| 137 | + [0x04b4] 0x30a8, | |
| 138 | + [0x04b5] 0x30aa, | |
| 139 | + [0x04b6] 0x30ab, | |
| 140 | + [0x04b7] 0x30ad, | |
| 141 | + [0x04b8] 0x30af, | |
| 142 | + [0x04b9] 0x30b1, | |
| 143 | + [0x04ba] 0x30b3, | |
| 144 | + [0x04bb] 0x30b5, | |
| 145 | + [0x04bc] 0x30b7, | |
| 146 | + [0x04bd] 0x30b9, | |
| 147 | + [0x04be] 0x30bb, | |
| 148 | + [0x04bf] 0x30bd, | |
| 149 | + [0x04c0] 0x30bf, | |
| 150 | + [0x04c1] 0x30c1, | |
| 151 | + [0x04c2] 0x30c4, | |
| 152 | + [0x04c3] 0x30c6, | |
| 153 | + [0x04c4] 0x30c8, | |
| 154 | + [0x04c5] 0x30ca, | |
| 155 | + [0x04c6] 0x30cb, | |
| 156 | + [0x04c7] 0x30cc, | |
| 157 | + [0x04c8] 0x30cd, | |
| 158 | + [0x04c9] 0x30ce, | |
| 159 | + [0x04ca] 0x30cf, | |
| 160 | + [0x04cb] 0x30d2, | |
| 161 | + [0x04cc] 0x30d5, | |
| 162 | + [0x04cd] 0x30d8, | |
| 163 | + [0x04ce] 0x30db, | |
| 164 | + [0x04cf] 0x30de, | |
| 165 | + [0x04d0] 0x30df, | |
| 166 | + [0x04d1] 0x30e0, | |
| 167 | + [0x04d2] 0x30e1, | |
| 168 | + [0x04d3] 0x30e2, | |
| 169 | + [0x04d4] 0x30e4, | |
| 170 | + [0x04d5] 0x30e6, | |
| 171 | + [0x04d6] 0x30e8, | |
| 172 | + [0x04d7] 0x30e9, | |
| 173 | + [0x04d8] 0x30ea, | |
| 174 | + [0x04d9] 0x30eb, | |
| 175 | + [0x04da] 0x30ec, | |
| 176 | + [0x04db] 0x30ed, | |
| 177 | + [0x04dc] 0x30ef, | |
| 178 | + [0x04dd] 0x30f3, | |
| 179 | + [0x04de] 0x309b, | |
| 180 | + [0x04df] 0x309c, | |
| 181 | + [0x05ac] 0x060c, | |
| 182 | + [0x05bb] 0x061b, | |
| 183 | + [0x05bf] 0x061f, | |
| 184 | + [0x05c1] 0x0621, | |
| 185 | + [0x05c2] 0x0622, | |
| 186 | + [0x05c3] 0x0623, | |
| 187 | + [0x05c4] 0x0624, | |
| 188 | + [0x05c5] 0x0625, | |
| 189 | + [0x05c6] 0x0626, | |
| 190 | + [0x05c7] 0x0627, | |
| 191 | + [0x05c8] 0x0628, | |
| 192 | + [0x05c9] 0x0629, | |
| 193 | + [0x05ca] 0x062a, | |
| 194 | + [0x05cb] 0x062b, | |
| 195 | + [0x05cc] 0x062c, | |
| 196 | + [0x05cd] 0x062d, | |
| 197 | + [0x05ce] 0x062e, | |
| 198 | + [0x05cf] 0x062f, | |
| 199 | + [0x05d0] 0x0630, | |
| 200 | + [0x05d1] 0x0631, | |
| 201 | + [0x05d2] 0x0632, | |
| 202 | + [0x05d3] 0x0633, | |
| 203 | + [0x05d4] 0x0634, | |
| 204 | + [0x05d5] 0x0635, | |
| 205 | + [0x05d6] 0x0636, | |
| 206 | + [0x05d7] 0x0637, | |
| 207 | + [0x05d8] 0x0638, | |
| 208 | + [0x05d9] 0x0639, | |
| 209 | + [0x05da] 0x063a, | |
| 210 | + [0x05e0] 0x0640, | |
| 211 | + [0x05e1] 0x0641, | |
| 212 | + [0x05e2] 0x0642, | |
| 213 | + [0x05e3] 0x0643, | |
| 214 | + [0x05e4] 0x0644, | |
| 215 | + [0x05e5] 0x0645, | |
| 216 | + [0x05e6] 0x0646, | |
| 217 | + [0x05e7] 0x0647, | |
| 218 | + [0x05e8] 0x0648, | |
| 219 | + [0x05e9] 0x0649, | |
| 220 | + [0x05ea] 0x064a, | |
| 221 | + [0x05eb] 0x064b, | |
| 222 | + [0x05ec] 0x064c, | |
| 223 | + [0x05ed] 0x064d, | |
| 224 | + [0x05ee] 0x064e, | |
| 225 | + [0x05ef] 0x064f, | |
| 226 | + [0x05f0] 0x0650, | |
| 227 | + [0x05f1] 0x0651, | |
| 228 | + [0x05f2] 0x0652, | |
| 229 | + [0x06a1] 0x0452, | |
| 230 | + [0x06a2] 0x0453, | |
| 231 | + [0x06a3] 0x0451, | |
| 232 | + [0x06a4] 0x0454, | |
| 233 | + [0x06a5] 0x0455, | |
| 234 | + [0x06a6] 0x0456, | |
| 235 | + [0x06a7] 0x0457, | |
| 236 | + [0x06a8] 0x0458, | |
| 237 | + [0x06a9] 0x0459, | |
| 238 | + [0x06aa] 0x045a, | |
| 239 | + [0x06ab] 0x045b, | |
| 240 | + [0x06ac] 0x045c, | |
| 241 | + [0x06ae] 0x045e, | |
| 242 | + [0x06af] 0x045f, | |
| 243 | + [0x06b0] 0x2116, | |
| 244 | + [0x06b1] 0x0402, | |
| 245 | + [0x06b2] 0x0403, | |
| 246 | + [0x06b3] 0x0401, | |
| 247 | + [0x06b4] 0x0404, | |
| 248 | + [0x06b5] 0x0405, | |
| 249 | + [0x06b6] 0x0406, | |
| 250 | + [0x06b7] 0x0407, | |
| 251 | + [0x06b8] 0x0408, | |
| 252 | + [0x06b9] 0x0409, | |
| 253 | + [0x06ba] 0x040a, | |
| 254 | + [0x06bb] 0x040b, | |
| 255 | + [0x06bc] 0x040c, | |
| 256 | + [0x06be] 0x040e, | |
| 257 | + [0x06bf] 0x040f, | |
| 258 | + [0x06c0] 0x044e, | |
| 259 | + [0x06c1] 0x0430, | |
| 260 | + [0x06c2] 0x0431, | |
| 261 | + [0x06c3] 0x0446, | |
| 262 | + [0x06c4] 0x0434, | |
| 263 | + [0x06c5] 0x0435, | |
| 264 | + [0x06c6] 0x0444, | |
| 265 | + [0x06c7] 0x0433, | |
| 266 | + [0x06c8] 0x0445, | |
| 267 | + [0x06c9] 0x0438, | |
| 268 | + [0x06ca] 0x0439, | |
| 269 | + [0x06cb] 0x043a, | |
| 270 | + [0x06cc] 0x043b, | |
| 271 | + [0x06cd] 0x043c, | |
| 272 | + [0x06ce] 0x043d, | |
| 273 | + [0x06cf] 0x043e, | |
| 274 | + [0x06d0] 0x043f, | |
| 275 | + [0x06d1] 0x044f, | |
| 276 | + [0x06d2] 0x0440, | |
| 277 | + [0x06d3] 0x0441, | |
| 278 | + [0x06d4] 0x0442, | |
| 279 | + [0x06d5] 0x0443, | |
| 280 | + [0x06d6] 0x0436, | |
| 281 | + [0x06d7] 0x0432, | |
| 282 | + [0x06d8] 0x044c, | |
| 283 | + [0x06d9] 0x044b, | |
| 284 | + [0x06da] 0x0437, | |
| 285 | + [0x06db] 0x0448, | |
| 286 | + [0x06dc] 0x044d, | |
| 287 | + [0x06dd] 0x0449, | |
| 288 | + [0x06de] 0x0447, | |
| 289 | + [0x06df] 0x044a, | |
| 290 | + [0x06e0] 0x042e, | |
| 291 | + [0x06e1] 0x0410, | |
| 292 | + [0x06e2] 0x0411, | |
| 293 | + [0x06e3] 0x0426, | |
| 294 | + [0x06e4] 0x0414, | |
| 295 | + [0x06e5] 0x0415, | |
| 296 | + [0x06e6] 0x0424, | |
| 297 | + [0x06e7] 0x0413, | |
| 298 | + [0x06e8] 0x0425, | |
| 299 | + [0x06e9] 0x0418, | |
| 300 | + [0x06ea] 0x0419, | |
| 301 | + [0x06eb] 0x041a, | |
| 302 | + [0x06ec] 0x041b, | |
| 303 | + [0x06ed] 0x041c, | |
| 304 | + [0x06ee] 0x041d, | |
| 305 | + [0x06ef] 0x041e, | |
| 306 | + [0x06f0] 0x041f, | |
| 307 | + [0x06f1] 0x042f, | |
| 308 | + [0x06f2] 0x0420, | |
| 309 | + [0x06f3] 0x0421, | |
| 310 | + [0x06f4] 0x0422, | |
| 311 | + [0x06f5] 0x0423, | |
| 312 | + [0x06f6] 0x0416, | |
| 313 | + [0x06f7] 0x0412, | |
| 314 | + [0x06f8] 0x042c, | |
| 315 | + [0x06f9] 0x042b, | |
| 316 | + [0x06fa] 0x0417, | |
| 317 | + [0x06fb] 0x0428, | |
| 318 | + [0x06fc] 0x042d, | |
| 319 | + [0x06fd] 0x0429, | |
| 320 | + [0x06fe] 0x0427, | |
| 321 | + [0x06ff] 0x042a, | |
| 322 | + [0x07a1] 0x0386, | |
| 323 | + [0x07a2] 0x0388, | |
| 324 | + [0x07a3] 0x0389, | |
| 325 | + [0x07a4] 0x038a, | |
| 326 | + [0x07a5] 0x03aa, | |
| 327 | + [0x07a7] 0x038c, | |
| 328 | + [0x07a8] 0x038e, | |
| 329 | + [0x07a9] 0x03ab, | |
| 330 | + [0x07ab] 0x038f, | |
| 331 | + [0x07ae] 0x0385, | |
| 332 | + [0x07af] 0x2015, | |
| 333 | + [0x07b1] 0x03ac, | |
| 334 | + [0x07b2] 0x03ad, | |
| 335 | + [0x07b3] 0x03ae, | |
| 336 | + [0x07b4] 0x03af, | |
| 337 | + [0x07b5] 0x03ca, | |
| 338 | + [0x07b6] 0x0390, | |
| 339 | + [0x07b7] 0x03cc, | |
| 340 | + [0x07b8] 0x03cd, | |
| 341 | + [0x07b9] 0x03cb, | |
| 342 | + [0x07ba] 0x03b0, | |
| 343 | + [0x07bb] 0x03ce, | |
| 344 | + [0x07c1] 0x0391, | |
| 345 | + [0x07c2] 0x0392, | |
| 346 | + [0x07c3] 0x0393, | |
| 347 | + [0x07c4] 0x0394, | |
| 348 | + [0x07c5] 0x0395, | |
| 349 | + [0x07c6] 0x0396, | |
| 350 | + [0x07c7] 0x0397, | |
| 351 | + [0x07c8] 0x0398, | |
| 352 | + [0x07c9] 0x0399, | |
| 353 | + [0x07ca] 0x039a, | |
| 354 | + [0x07cb] 0x039b, | |
| 355 | + [0x07cc] 0x039c, | |
| 356 | + [0x07cd] 0x039d, | |
| 357 | + [0x07ce] 0x039e, | |
| 358 | + [0x07cf] 0x039f, | |
| 359 | + [0x07d0] 0x03a0, | |
| 360 | + [0x07d1] 0x03a1, | |
| 361 | + [0x07d2] 0x03a3, | |
| 362 | + [0x07d4] 0x03a4, | |
| 363 | + [0x07d5] 0x03a5, | |
| 364 | + [0x07d6] 0x03a6, | |
| 365 | + [0x07d7] 0x03a7, | |
| 366 | + [0x07d8] 0x03a8, | |
| 367 | + [0x07d9] 0x03a9, | |
| 368 | + [0x07e1] 0x03b1, | |
| 369 | + [0x07e2] 0x03b2, | |
| 370 | + [0x07e3] 0x03b3, | |
| 371 | + [0x07e4] 0x03b4, | |
| 372 | + [0x07e5] 0x03b5, | |
| 373 | + [0x07e6] 0x03b6, | |
| 374 | + [0x07e7] 0x03b7, | |
| 375 | + [0x07e8] 0x03b8, | |
| 376 | + [0x07e9] 0x03b9, | |
| 377 | + [0x07ea] 0x03ba, | |
| 378 | + [0x07eb] 0x03bb, | |
| 379 | + [0x07ec] 0x03bc, | |
| 380 | + [0x07ed] 0x03bd, | |
| 381 | + [0x07ee] 0x03be, | |
| 382 | + [0x07ef] 0x03bf, | |
| 383 | + [0x07f0] 0x03c0, | |
| 384 | + [0x07f1] 0x03c1, | |
| 385 | + [0x07f2] 0x03c3, | |
| 386 | + [0x07f3] 0x03c2, | |
| 387 | + [0x07f4] 0x03c4, | |
| 388 | + [0x07f5] 0x03c5, | |
| 389 | + [0x07f6] 0x03c6, | |
| 390 | + [0x07f7] 0x03c7, | |
| 391 | + [0x07f8] 0x03c8, | |
| 392 | + [0x07f9] 0x03c9, | |
| 393 | + [0x08a4] 0x2320, | |
| 394 | + [0x08a5] 0x2321, | |
| 395 | + [0x08a6] 0x2502, | |
| 396 | + [0x08bc] 0x2264, | |
| 397 | + [0x08bd] 0x2260, | |
| 398 | + [0x08be] 0x2265, | |
| 399 | + [0x08bf] 0x222b, | |
| 400 | + [0x08c0] 0x2234, | |
| 401 | + [0x08c1] 0x221d, | |
| 402 | + [0x08c2] 0x221e, | |
| 403 | + [0x08c5] 0x2207, | |
| 404 | + [0x08c8] 0x2245, | |
| 405 | + [0x08cd] 0x21d4, | |
| 406 | + [0x08ce] 0x21d2, | |
| 407 | + [0x08cf] 0x2261, | |
| 408 | + [0x08d6] 0x221a, | |
| 409 | + [0x08da] 0x2282, | |
| 410 | + [0x08db] 0x2283, | |
| 411 | + [0x08dc] 0x2229, | |
| 412 | + [0x08dd] 0x222a, | |
| 413 | + [0x08de] 0x2227, | |
| 414 | + [0x08df] 0x2228, | |
| 415 | + [0x08ef] 0x2202, | |
| 416 | + [0x08f6] 0x0192, | |
| 417 | + [0x08fb] 0x2190, | |
| 418 | + [0x08fc] 0x2191, | |
| 419 | + [0x08fd] 0x2192, | |
| 420 | + [0x08fe] 0x2193, | |
| 421 | + [0x09df] 0x2422, | |
| 422 | + [0x09e0] 0x25c6, | |
| 423 | + [0x09e1] 0x2592, | |
| 424 | + [0x09e2] 0x2409, | |
| 425 | + [0x09e3] 0x240c, | |
| 426 | + [0x09e4] 0x240d, | |
| 427 | + [0x09e5] 0x240a, | |
| 428 | + [0x09e8] 0x2424, | |
| 429 | + [0x09e9] 0x240b, | |
| 430 | + [0x09ea] 0x2518, | |
| 431 | + [0x09eb] 0x2510, | |
| 432 | + [0x09ec] 0x250c, | |
| 433 | + [0x09ed] 0x2514, | |
| 434 | + [0x09ee] 0x253c, | |
| 435 | + [0x09f1] 0x2500, | |
| 436 | + [0x09f4] 0x251c, | |
| 437 | + [0x09f5] 0x2524, | |
| 438 | + [0x09f6] 0x2534, | |
| 439 | + [0x09f7] 0x252c, | |
| 440 | + [0x09f8] 0x2502, | |
| 441 | + [0x0aa1] 0x2003, | |
| 442 | + [0x0aa2] 0x2002, | |
| 443 | + [0x0aa3] 0x2004, | |
| 444 | + [0x0aa4] 0x2005, | |
| 445 | + [0x0aa5] 0x2007, | |
| 446 | + [0x0aa6] 0x2008, | |
| 447 | + [0x0aa7] 0x2009, | |
| 448 | + [0x0aa8] 0x200a, | |
| 449 | + [0x0aa9] 0x2014, | |
| 450 | + [0x0aaa] 0x2013, | |
| 451 | + [0x0aae] 0x2026, | |
| 452 | + [0x0ab0] 0x2153, | |
| 453 | + [0x0ab1] 0x2154, | |
| 454 | + [0x0ab2] 0x2155, | |
| 455 | + [0x0ab3] 0x2156, | |
| 456 | + [0x0ab4] 0x2157, | |
| 457 | + [0x0ab5] 0x2158, | |
| 458 | + [0x0ab6] 0x2159, | |
| 459 | + [0x0ab7] 0x215a, | |
| 460 | + [0x0ab8] 0x2105, | |
| 461 | + [0x0abb] 0x2012, | |
| 462 | + [0x0abc] 0x2329, | |
| 463 | + [0x0abd] 0x002e, | |
| 464 | + [0x0abe] 0x232a, | |
| 465 | + [0x0ac3] 0x215b, | |
| 466 | + [0x0ac4] 0x215c, | |
| 467 | + [0x0ac5] 0x215d, | |
| 468 | + [0x0ac6] 0x215e, | |
| 469 | + [0x0ac9] 0x2122, | |
| 470 | + [0x0aca] 0x2613, | |
| 471 | + [0x0acc] 0x25c1, | |
| 472 | + [0x0acd] 0x25b7, | |
| 473 | + [0x0ace] 0x25cb, | |
| 474 | + [0x0acf] 0x25a1, | |
| 475 | + [0x0ad0] 0x2018, | |
| 476 | + [0x0ad1] 0x2019, | |
| 477 | + [0x0ad2] 0x201c, | |
| 478 | + [0x0ad3] 0x201d, | |
| 479 | + [0x0ad4] 0x211e, | |
| 480 | + [0x0ad6] 0x2032, | |
| 481 | + [0x0ad7] 0x2033, | |
| 482 | + [0x0ad9] 0x271d, | |
| 483 | + [0x0adb] 0x25ac, | |
| 484 | + [0x0adc] 0x25c0, | |
| 485 | + [0x0add] 0x25b6, | |
| 486 | + [0x0ade] 0x25cf, | |
| 487 | + [0x0adf] 0x25a0, | |
| 488 | + [0x0ae0] 0x25e6, | |
| 489 | + [0x0ae1] 0x25ab, | |
| 490 | + [0x0ae2] 0x25ad, | |
| 491 | + [0x0ae3] 0x25b3, | |
| 492 | + [0x0ae4] 0x25bd, | |
| 493 | + [0x0ae5] 0x2606, | |
| 494 | + [0x0ae6] 0x2022, | |
| 495 | + [0x0ae7] 0x25aa, | |
| 496 | + [0x0ae8] 0x25b2, | |
| 497 | + [0x0ae9] 0x25bc, | |
| 498 | + [0x0aea] 0x261c, | |
| 499 | + [0x0aeb] 0x261e, | |
| 500 | + [0x0aec] 0x2663, | |
| 501 | + [0x0aed] 0x2666, | |
| 502 | + [0x0aee] 0x2665, | |
| 503 | + [0x0af0] 0x2720, | |
| 504 | + [0x0af1] 0x2020, | |
| 505 | + [0x0af2] 0x2021, | |
| 506 | + [0x0af3] 0x2713, | |
| 507 | + [0x0af4] 0x2717, | |
| 508 | + [0x0af5] 0x266f, | |
| 509 | + [0x0af6] 0x266d, | |
| 510 | + [0x0af7] 0x2642, | |
| 511 | + [0x0af8] 0x2640, | |
| 512 | + [0x0af9] 0x260e, | |
| 513 | + [0x0afa] 0x2315, | |
| 514 | + [0x0afb] 0x2117, | |
| 515 | + [0x0afc] 0x2038, | |
| 516 | + [0x0afd] 0x201a, | |
| 517 | + [0x0afe] 0x201e, | |
| 518 | + [0x0ba3] 0x003c, | |
| 519 | + [0x0ba6] 0x003e, | |
| 520 | + [0x0ba8] 0x2228, | |
| 521 | + [0x0ba9] 0x2227, | |
| 522 | + [0x0bc0] 0x00af, | |
| 523 | + [0x0bc2] 0x22a4, | |
| 524 | + [0x0bc3] 0x2229, | |
| 525 | + [0x0bc4] 0x230a, | |
| 526 | + [0x0bc6] 0x005f, | |
| 527 | + [0x0bca] 0x2218, | |
| 528 | + [0x0bcc] 0x2395, | |
| 529 | + [0x0bce] 0x22a5, | |
| 530 | + [0x0bcf] 0x25cb, | |
| 531 | + [0x0bd3] 0x2308, | |
| 532 | + [0x0bd6] 0x222a, | |
| 533 | + [0x0bd8] 0x2283, | |
| 534 | + [0x0bda] 0x2282, | |
| 535 | + [0x0bdc] 0x22a3, | |
| 536 | + [0x0bfc] 0x22a2, | |
| 537 | + [0x0cdf] 0x2017, | |
| 538 | + [0x0ce0] 0x05d0, | |
| 539 | + [0x0ce1] 0x05d1, | |
| 540 | + [0x0ce2] 0x05d2, | |
| 541 | + [0x0ce3] 0x05d3, | |
| 542 | + [0x0ce4] 0x05d4, | |
| 543 | + [0x0ce5] 0x05d5, | |
| 544 | + [0x0ce6] 0x05d6, | |
| 545 | + [0x0ce7] 0x05d7, | |
| 546 | + [0x0ce8] 0x05d8, | |
| 547 | + [0x0ce9] 0x05d9, | |
| 548 | + [0x0cea] 0x05da, | |
| 549 | + [0x0ceb] 0x05db, | |
| 550 | + [0x0cec] 0x05dc, | |
| 551 | + [0x0ced] 0x05dd, | |
| 552 | + [0x0cee] 0x05de, | |
| 553 | + [0x0cef] 0x05df, | |
| 554 | + [0x0cf0] 0x05e0, | |
| 555 | + [0x0cf1] 0x05e1, | |
| 556 | + [0x0cf2] 0x05e2, | |
| 557 | + [0x0cf3] 0x05e3, | |
| 558 | + [0x0cf4] 0x05e4, | |
| 559 | + [0x0cf5] 0x05e5, | |
| 560 | + [0x0cf6] 0x05e6, | |
| 561 | + [0x0cf7] 0x05e7, | |
| 562 | + [0x0cf8] 0x05e8, | |
| 563 | + [0x0cf9] 0x05e9, | |
| 564 | + [0x0cfa] 0x05ea, | |
| 565 | + [0x0da1] 0x0e01, | |
| 566 | + [0x0da2] 0x0e02, | |
| 567 | + [0x0da3] 0x0e03, | |
| 568 | + [0x0da4] 0x0e04, | |
| 569 | + [0x0da5] 0x0e05, | |
| 570 | + [0x0da6] 0x0e06, | |
| 571 | + [0x0da7] 0x0e07, | |
| 572 | + [0x0da8] 0x0e08, | |
| 573 | + [0x0da9] 0x0e09, | |
| 574 | + [0x0daa] 0x0e0a, | |
| 575 | + [0x0dab] 0x0e0b, | |
| 576 | + [0x0dac] 0x0e0c, | |
| 577 | + [0x0dad] 0x0e0d, | |
| 578 | + [0x0dae] 0x0e0e, | |
| 579 | + [0x0daf] 0x0e0f, | |
| 580 | + [0x0db0] 0x0e10, | |
| 581 | + [0x0db1] 0x0e11, | |
| 582 | + [0x0db2] 0x0e12, | |
| 583 | + [0x0db3] 0x0e13, | |
| 584 | + [0x0db4] 0x0e14, | |
| 585 | + [0x0db5] 0x0e15, | |
| 586 | + [0x0db6] 0x0e16, | |
| 587 | + [0x0db7] 0x0e17, | |
| 588 | + [0x0db8] 0x0e18, | |
| 589 | + [0x0db9] 0x0e19, | |
| 590 | + [0x0dba] 0x0e1a, | |
| 591 | + [0x0dbb] 0x0e1b, | |
| 592 | + [0x0dbc] 0x0e1c, | |
| 593 | + [0x0dbd] 0x0e1d, | |
| 594 | + [0x0dbe] 0x0e1e, | |
| 595 | + [0x0dbf] 0x0e1f, | |
| 596 | + [0x0dc0] 0x0e20, | |
| 597 | + [0x0dc1] 0x0e21, | |
| 598 | + [0x0dc2] 0x0e22, | |
| 599 | + [0x0dc3] 0x0e23, | |
| 600 | + [0x0dc4] 0x0e24, | |
| 601 | + [0x0dc5] 0x0e25, | |
| 602 | + [0x0dc6] 0x0e26, | |
| 603 | + [0x0dc7] 0x0e27, | |
| 604 | + [0x0dc8] 0x0e28, | |
| 605 | + [0x0dc9] 0x0e29, | |
| 606 | + [0x0dca] 0x0e2a, | |
| 607 | + [0x0dcb] 0x0e2b, | |
| 608 | + [0x0dcc] 0x0e2c, | |
| 609 | + [0x0dcd] 0x0e2d, | |
| 610 | + [0x0dce] 0x0e2e, | |
| 611 | + [0x0dcf] 0x0e2f, | |
| 612 | + [0x0dd0] 0x0e30, | |
| 613 | + [0x0dd1] 0x0e31, | |
| 614 | + [0x0dd2] 0x0e32, | |
| 615 | + [0x0dd3] 0x0e33, | |
| 616 | + [0x0dd4] 0x0e34, | |
| 617 | + [0x0dd5] 0x0e35, | |
| 618 | + [0x0dd6] 0x0e36, | |
| 619 | + [0x0dd7] 0x0e37, | |
| 620 | + [0x0dd8] 0x0e38, | |
| 621 | + [0x0dd9] 0x0e39, | |
| 622 | + [0x0dda] 0x0e3a, | |
| 623 | + [0x0dde] 0x0e3e, | |
| 624 | + [0x0ddf] 0x0e3f, | |
| 625 | + [0x0de0] 0x0e40, | |
| 626 | + [0x0de1] 0x0e41, | |
| 627 | + [0x0de2] 0x0e42, | |
| 628 | + [0x0de3] 0x0e43, | |
| 629 | + [0x0de4] 0x0e44, | |
| 630 | + [0x0de5] 0x0e45, | |
| 631 | + [0x0de6] 0x0e46, | |
| 632 | + [0x0de7] 0x0e47, | |
| 633 | + [0x0de8] 0x0e48, | |
| 634 | + [0x0de9] 0x0e49, | |
| 635 | + [0x0dea] 0x0e4a, | |
| 636 | + [0x0deb] 0x0e4b, | |
| 637 | + [0x0dec] 0x0e4c, | |
| 638 | + [0x0ded] 0x0e4d, | |
| 639 | + [0x0df0] 0x0e50, | |
| 640 | + [0x0df1] 0x0e51, | |
| 641 | + [0x0df2] 0x0e52, | |
| 642 | + [0x0df3] 0x0e53, | |
| 643 | + [0x0df4] 0x0e54, | |
| 644 | + [0x0df5] 0x0e55, | |
| 645 | + [0x0df6] 0x0e56, | |
| 646 | + [0x0df7] 0x0e57, | |
| 647 | + [0x0df8] 0x0e58, | |
| 648 | + [0x0df9] 0x0e59, | |
| 649 | + [0x0ea1] 0x3131, | |
| 650 | + [0x0ea2] 0x3132, | |
| 651 | + [0x0ea3] 0x3133, | |
| 652 | + [0x0ea4] 0x3134, | |
| 653 | + [0x0ea5] 0x3135, | |
| 654 | + [0x0ea6] 0x3136, | |
| 655 | + [0x0ea7] 0x3137, | |
| 656 | + [0x0ea8] 0x3138, | |
| 657 | + [0x0ea9] 0x3139, | |
| 658 | + [0x0eaa] 0x313a, | |
| 659 | + [0x0eab] 0x313b, | |
| 660 | + [0x0eac] 0x313c, | |
| 661 | + [0x0ead] 0x313d, | |
| 662 | + [0x0eae] 0x313e, | |
| 663 | + [0x0eaf] 0x313f, | |
| 664 | + [0x0eb0] 0x3140, | |
| 665 | + [0x0eb1] 0x3141, | |
| 666 | + [0x0eb2] 0x3142, | |
| 667 | + [0x0eb3] 0x3143, | |
| 668 | + [0x0eb4] 0x3144, | |
| 669 | + [0x0eb5] 0x3145, | |
| 670 | + [0x0eb6] 0x3146, | |
| 671 | + [0x0eb7] 0x3147, | |
| 672 | + [0x0eb8] 0x3148, | |
| 673 | + [0x0eb9] 0x3149, | |
| 674 | + [0x0eba] 0x314a, | |
| 675 | + [0x0ebb] 0x314b, | |
| 676 | + [0x0ebc] 0x314c, | |
| 677 | + [0x0ebd] 0x314d, | |
| 678 | + [0x0ebe] 0x314e, | |
| 679 | + [0x0ebf] 0x314f, | |
| 680 | + [0x0ec0] 0x3150, | |
| 681 | + [0x0ec1] 0x3151, | |
| 682 | + [0x0ec2] 0x3152, | |
| 683 | + [0x0ec3] 0x3153, | |
| 684 | + [0x0ec4] 0x3154, | |
| 685 | + [0x0ec5] 0x3155, | |
| 686 | + [0x0ec6] 0x3156, | |
| 687 | + [0x0ec7] 0x3157, | |
| 688 | + [0x0ec8] 0x3158, | |
| 689 | + [0x0ec9] 0x3159, | |
| 690 | + [0x0eca] 0x315a, | |
| 691 | + [0x0ecb] 0x315b, | |
| 692 | + [0x0ecc] 0x315c, | |
| 693 | + [0x0ecd] 0x315d, | |
| 694 | + [0x0ece] 0x315e, | |
| 695 | + [0x0ecf] 0x315f, | |
| 696 | + [0x0ed0] 0x3160, | |
| 697 | + [0x0ed1] 0x3161, | |
| 698 | + [0x0ed2] 0x3162, | |
| 699 | + [0x0ed3] 0x3163, | |
| 700 | + [0x0ed4] 0x11a8, | |
| 701 | + [0x0ed5] 0x11a9, | |
| 702 | + [0x0ed6] 0x11aa, | |
| 703 | + [0x0ed7] 0x11ab, | |
| 704 | + [0x0ed8] 0x11ac, | |
| 705 | + [0x0ed9] 0x11ad, | |
| 706 | + [0x0eda] 0x11ae, | |
| 707 | + [0x0edb] 0x11af, | |
| 708 | + [0x0edc] 0x11b0, | |
| 709 | + [0x0edd] 0x11b1, | |
| 710 | + [0x0ede] 0x11b2, | |
| 711 | + [0x0edf] 0x11b3, | |
| 712 | + [0x0ee0] 0x11b4, | |
| 713 | + [0x0ee1] 0x11b5, | |
| 714 | + [0x0ee2] 0x11b6, | |
| 715 | + [0x0ee3] 0x11b7, | |
| 716 | + [0x0ee4] 0x11b8, | |
| 717 | + [0x0ee5] 0x11b9, | |
| 718 | + [0x0ee6] 0x11ba, | |
| 719 | + [0x0ee7] 0x11bb, | |
| 720 | + [0x0ee8] 0x11bc, | |
| 721 | + [0x0ee9] 0x11bd, | |
| 722 | + [0x0eea] 0x11be, | |
| 723 | + [0x0eeb] 0x11bf, | |
| 724 | + [0x0eec] 0x11c0, | |
| 725 | + [0x0eed] 0x11c1, | |
| 726 | + [0x0eee] 0x11c2, | |
| 727 | + [0x0eef] 0x316d, | |
| 728 | + [0x0ef0] 0x3171, | |
| 729 | + [0x0ef1] 0x3178, | |
| 730 | + [0x0ef2] 0x317f, | |
| 731 | + [0x0ef4] 0x3184, | |
| 732 | + [0x0ef5] 0x3186, | |
| 733 | + [0x0ef6] 0x318d, | |
| 734 | + [0x0ef7] 0x318e, | |
| 735 | + [0x0ef8] 0x11eb, | |
| 736 | + [0x0efa] 0x11f9, | |
| 737 | + [0x0eff] 0x20a9, | |
| 738 | + [0x13bc] 0x0152, | |
| 739 | + [0x13bd] 0x0153, | |
| 740 | + [0x13be] 0x0178, | |
| 741 | + [0x20a0] 0x20a0, | |
| 742 | + [0x20a1] 0x20a1, | |
| 743 | + [0x20a2] 0x20a2, | |
| 744 | + [0x20a3] 0x20a3, | |
| 745 | + [0x20a4] 0x20a4, | |
| 746 | + [0x20a5] 0x20a5, | |
| 747 | + [0x20a6] 0x20a6, | |
| 748 | + [0x20a7] 0x20a7, | |
| 749 | + [0x20a8] 0x20a8, | |
| 750 | + [0x20a9] 0x20a9, | |
| 751 | + [0x20aa] 0x20aa, | |
| 752 | + [0x20ab] 0x20ab, | |
| 753 | + [0x20ac] 0x20ac, | |
| 754 | +}; | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +#include <u.h> | |
| 2 | +#include <libc.h> | |
| 3 | +#include <draw.h> | |
| 4 | +#include <memdraw.h> | |
| 5 | +#include "xmem.h" | |
| 6 | + | |
| 7 | +int | |
| 8 | +loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) | |
| 9 | +{ | |
| 10 | + int n; | |
| 11 | + | |
| 12 | + n = _loadmemimage(i, r, data, ndata); | |
| 13 | + if(n > 0 && i->X) | |
| 14 | + putXdata(i, r); | |
| 15 | + return n; | |
| 16 | +} | |
| @@ -0,0 +1,1094 @@ | ||
| 1 | +#include <sys/types.h> | |
| 2 | +#include <sys/stat.h> | |
| 3 | +#include <fcntl.h> | |
| 4 | +#include <termios.h> | |
| 5 | +#include <stdio.h> | |
| 6 | + | |
| 7 | +#include <X11/Xlib.h> | |
| 8 | +#include <X11/Xatom.h> | |
| 9 | +#include <X11/Xutil.h> | |
| 10 | +#include <X11/keysym.h> | |
| 11 | + | |
| 12 | +#include "keysym2ucs.h" | |
| 13 | + | |
| 14 | +/* | |
| 15 | + * alias defs for image types to overcome name conflicts | |
| 16 | + */ | |
| 17 | +#define Point IPoint | |
| 18 | +#define Rectangle IRectangle | |
| 19 | +#define Display IDisplay | |
| 20 | +#define Font IFont | |
| 21 | +#define Screen IScreen | |
| 22 | + | |
| 23 | +#include <u.h> | |
| 24 | +#include <libc.h> | |
| 25 | +#include <draw.h> | |
| 26 | +#include <memdraw.h> | |
| 27 | +#include <keyboard.h> | |
| 28 | +#include "dat.h" | |
| 29 | +#include "fns.h" | |
| 30 | +#include "screen.h" | |
| 31 | + | |
| 32 | +#undef time | |
| 33 | +#undef Point | |
| 34 | +#undef Rectangle | |
| 35 | +#undef Display | |
| 36 | +#undef Font | |
| 37 | +#undef Screen | |
| 38 | + | |
| 39 | +typedef struct ICursor ICursor; | |
| 40 | +struct ICursor | |
| 41 | +{ | |
| 42 | + int w; | |
| 43 | + int h; | |
| 44 | + int hotx; | |
| 45 | + int hoty; | |
| 46 | + char *src; | |
| 47 | + char *mask; | |
| 48 | +}; | |
| 49 | + | |
| 50 | + | |
| 51 | +#define ABS(x) ((x) < 0 ? -(x) : (x)) | |
| 52 | + | |
| 53 | +enum | |
| 54 | +{ | |
| 55 | + DblTime = 300 /* double click time in msec */ | |
| 56 | +}; | |
| 57 | + | |
| 58 | +XColor map[256]; /* Plan 9 colormap array */ | |
| 59 | +XColor map7[128]; /* Plan 9 colormap array */ | |
| 60 | +uchar map7to8[128][2]; | |
| 61 | +Colormap xcmap; /* Default shared colormap */ | |
| 62 | +int plan9tox11[256]; /* Values for mapping between */ | |
| 63 | +int x11toplan9[256]; /* X11 and Plan 9 */ | |
| 64 | +int x24bitswap = 0; /* swap endian for 24bit RGB */ | |
| 65 | +int xtblbit; | |
| 66 | +extern int mousequeue; | |
| 67 | + | |
| 68 | +/* for copy/paste, lifted from plan9ports */ | |
| 69 | +Atom clipboard; | |
| 70 | +Atom utf8string; | |
| 71 | +Atom targets; | |
| 72 | +Atom text; | |
| 73 | +Atom compoundtext; | |
| 74 | + | |
| 75 | +static XModifierKeymap *modmap; | |
| 76 | +static int keypermod; | |
| 77 | +static Drawable xdrawable; | |
| 78 | +/* static Atom wm_take_focus; */ | |
| 79 | +static void xexpose(XEvent*); | |
| 80 | +static void xmouse(XEvent*); | |
| 81 | +static void xkeyboard(XEvent*); | |
| 82 | +static void xmapping(XEvent*); | |
| 83 | +static void xdestroy(XEvent*); | |
| 84 | +static void xselect(XEvent*); | |
| 85 | +static void xproc(void*); | |
| 86 | +static Memimage* xinitscreen(void); | |
| 87 | +static void initmap(Window); | |
| 88 | +static GC creategc(Drawable); | |
| 89 | +static void graphicscmap(XColor*); | |
| 90 | + int xscreendepth; | |
| 91 | + Drawable xscreenid; | |
| 92 | + Display* xdisplay; | |
| 93 | + Display* xkmcon; | |
| 94 | + Display* xsnarfcon; | |
| 95 | + Visual *xvis; | |
| 96 | + GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc; | |
| 97 | + GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0; | |
| 98 | + ulong xblack; | |
| 99 | + ulong xwhite; | |
| 100 | + ulong xscreenchan; | |
| 101 | + | |
| 102 | +extern Memimage* xallocmemimage(IRectangle, ulong, int); | |
| 103 | +Memimage *gscreen; | |
| 104 | +Screeninfo screen; | |
| 105 | +XImage *ximage; | |
| 106 | + | |
| 107 | +void | |
| 108 | +screeninit(void) | |
| 109 | +{ | |
| 110 | + _memmkcmap(); | |
| 111 | + | |
| 112 | + gscreen = xinitscreen(); | |
| 113 | + kproc("xscreen", xproc, nil); | |
| 114 | + | |
| 115 | + memimageinit(); | |
| 116 | + terminit(); | |
| 117 | + flushmemscreen(gscreen->r); | |
| 118 | +} | |
| 119 | + | |
| 120 | +uchar* | |
| 121 | +attachscreen(IRectangle *r, ulong *chan, int *depth, | |
| 122 | + int *width, int *softscreen, void **X) | |
| 123 | +{ | |
| 124 | + *r = gscreen->r; | |
| 125 | + *chan = gscreen->chan; | |
| 126 | + *depth = gscreen->depth; | |
| 127 | + *width = gscreen->width; | |
| 128 | + *X = gscreen->X; | |
| 129 | + *softscreen = 1; | |
| 130 | + | |
| 131 | + return gscreen->data->bdata; | |
| 132 | +} | |
| 133 | + | |
| 134 | +void | |
| 135 | +flushmemscreen(IRectangle r) | |
| 136 | +{ | |
| 137 | + if(r.min.x >= r.max.x || r.min.y >= r.max.y) | |
| 138 | + return; | |
| 139 | + XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y); | |
| 140 | + XFlush(xdisplay); | |
| 141 | +} | |
| 142 | + | |
| 143 | +static int | |
| 144 | +revbyte(int b) | |
| 145 | +{ | |
| 146 | + int r; | |
| 147 | + | |
| 148 | + r = 0; | |
| 149 | + r |= (b&0x01) << 7; | |
| 150 | + r |= (b&0x02) << 5; | |
| 151 | + r |= (b&0x04) << 3; | |
| 152 | + r |= (b&0x08) << 1; | |
| 153 | + r |= (b&0x10) >> 1; | |
| 154 | + r |= (b&0x20) >> 3; | |
| 155 | + r |= (b&0x40) >> 5; | |
| 156 | + r |= (b&0x80) >> 7; | |
| 157 | + return r; | |
| 158 | +} | |
| 159 | + | |
| 160 | +void | |
| 161 | +mouseset(IPoint xy) | |
| 162 | +{ | |
| 163 | + XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y); | |
| 164 | + XFlush(xdisplay); | |
| 165 | +} | |
| 166 | + | |
| 167 | +static Cursor xcursor; | |
| 168 | + | |
| 169 | +void | |
| 170 | +setcursor(void) | |
| 171 | +{ | |
| 172 | + Cursor xc; | |
| 173 | + XColor fg, bg; | |
| 174 | + Pixmap xsrc, xmask; | |
| 175 | + int i; | |
| 176 | + uchar src[2*16], mask[2*16]; | |
| 177 | + | |
| 178 | + for(i=0; i<2*16; i++){ | |
| 179 | + src[i] = revbyte(cursor.set[i]); | |
| 180 | + mask[i] = revbyte(cursor.set[i] | cursor.clr[i]); | |
| 181 | + } | |
| 182 | + | |
| 183 | + fg = map[0]; | |
| 184 | + bg = map[255]; | |
| 185 | + xsrc = XCreateBitmapFromData(xdisplay, xdrawable, src, 16, 16); | |
| 186 | + xmask = XCreateBitmapFromData(xdisplay, xdrawable, mask, 16, 16); | |
| 187 | + xc = XCreatePixmapCursor(xdisplay, xsrc, xmask, &fg, &bg, -cursor.offset.x, -cursor.offset.y); | |
| 188 | + if(xc != 0) { | |
| 189 | + XDefineCursor(xdisplay, xdrawable, xc); | |
| 190 | + if(xcursor != 0) | |
| 191 | + XFreeCursor(xdisplay, xcursor); | |
| 192 | + xcursor = xc; | |
| 193 | + } | |
| 194 | + XFreePixmap(xdisplay, xsrc); | |
| 195 | + XFreePixmap(xdisplay, xmask); | |
| 196 | + XFlush(xdisplay); | |
| 197 | +} | |
| 198 | + | |
| 199 | +void | |
| 200 | +cursorarrow(void) | |
| 201 | +{ | |
| 202 | + if(xcursor != 0){ | |
| 203 | + XFreeCursor(xdisplay, xcursor); | |
| 204 | + xcursor = 0; | |
| 205 | + } | |
| 206 | + XUndefineCursor(xdisplay, xdrawable); | |
| 207 | + XFlush(xdisplay); | |
| 208 | +} | |
| 209 | + | |
| 210 | +static void | |
| 211 | +xproc(void *arg) | |
| 212 | +{ | |
| 213 | + ulong mask; | |
| 214 | + XEvent event; | |
| 215 | + | |
| 216 | + mask = KeyPressMask| | |
| 217 | + ButtonPressMask| | |
| 218 | + ButtonReleaseMask| | |
| 219 | + PointerMotionMask| | |
| 220 | + Button1MotionMask| | |
| 221 | + Button2MotionMask| | |
| 222 | + Button3MotionMask| | |
| 223 | + Button4MotionMask| | |
| 224 | + Button5MotionMask| | |
| 225 | + ExposureMask| | |
| 226 | + StructureNotifyMask; | |
| 227 | + | |
| 228 | + XSelectInput(xkmcon, xdrawable, mask); | |
| 229 | + for(;;) { | |
| 230 | + //XWindowEvent(xkmcon, xdrawable, mask, &event); | |
| 231 | + XNextEvent(xkmcon, &event); | |
| 232 | + xselect(&event); | |
| 233 | + xkeyboard(&event); | |
| 234 | + xmouse(&event); | |
| 235 | + xexpose(&event); | |
| 236 | + xmapping(&event); | |
| 237 | + xdestroy(&event); | |
| 238 | + } | |
| 239 | +} | |
| 240 | + | |
| 241 | +static int | |
| 242 | +shutup(Display *d, XErrorEvent *e) | |
| 243 | +{ | |
| 244 | + char buf[200]; | |
| 245 | + iprint("X error: error code=%d, request_code=%d, minor=%d\n", e->error_code, e->request_code, e->minor_code); | |
| 246 | + XGetErrorText(d, e->error_code, buf, sizeof(buf)); | |
| 247 | + iprint("%s\n", buf); | |
| 248 | + USED(d); | |
| 249 | + USED(e); | |
| 250 | + return 0; | |
| 251 | +} | |
| 252 | + | |
| 253 | +static int | |
| 254 | +panicshutup(Display *d) | |
| 255 | +{ | |
| 256 | + panic("x error"); | |
| 257 | + return -1; | |
| 258 | +} | |
| 259 | + | |
| 260 | +static Memimage* | |
| 261 | +xinitscreen(void) | |
| 262 | +{ | |
| 263 | + Memimage *gscreen; | |
| 264 | + int i, xsize, ysize, pmid; | |
| 265 | + char *argv[2]; | |
| 266 | + char *disp_val; | |
| 267 | + Window rootwin; | |
| 268 | + IRectangle r; | |
| 269 | + XWMHints hints; | |
| 270 | + Screen *screen; | |
| 271 | + XVisualInfo xvi; | |
| 272 | + int rootscreennum; | |
| 273 | + XTextProperty name; | |
| 274 | + XClassHint classhints; | |
| 275 | + XSizeHints normalhints; | |
| 276 | + XSetWindowAttributes attrs; | |
| 277 | + XPixmapFormatValues *pfmt; | |
| 278 | + int n; | |
| 279 | + Memdata *md; | |
| 280 | + | |
| 281 | + xscreenid = 0; | |
| 282 | + xdrawable = 0; | |
| 283 | + | |
| 284 | + xdisplay = XOpenDisplay(NULL); | |
| 285 | + if(xdisplay == 0){ | |
| 286 | + disp_val = getenv("DISPLAY"); | |
| 287 | + if(disp_val == 0) | |
| 288 | + disp_val = "not set"; | |
| 289 | + iprint("drawterm: open %r, DISPLAY is %s\n", disp_val); | |
| 290 | + exit(0); | |
| 291 | + } | |
| 292 | + | |
| 293 | + XSetErrorHandler(shutup); | |
| 294 | + XSetIOErrorHandler(panicshutup); | |
| 295 | + rootscreennum = DefaultScreen(xdisplay); | |
| 296 | + rootwin = DefaultRootWindow(xdisplay); | |
| 297 | + | |
| 298 | + xscreendepth = DefaultDepth(xdisplay, rootscreennum); | |
| 299 | + if(XMatchVisualInfo(xdisplay, rootscreennum, 16, TrueColor, &xvi) | |
| 300 | + || XMatchVisualInfo(xdisplay, rootscreennum, 16, DirectColor, &xvi)){ | |
| 301 | + xvis = xvi.visual; | |
| 302 | + xscreendepth = 16; | |
| 303 | + xtblbit = 1; | |
| 304 | + } | |
| 305 | + else if(XMatchVisualInfo(xdisplay, rootscreennum, 24, TrueColor, &xvi) | |
| 306 | + || XMatchVisualInfo(xdisplay, rootscreennum, 24, DirectColor, &xvi)){ | |
| 307 | + xvis = xvi.visual; | |
| 308 | + xscreendepth = 24; | |
| 309 | + xtblbit = 1; | |
| 310 | + } | |
| 311 | + else if(XMatchVisualInfo(xdisplay, rootscreennum, 8, PseudoColor, &xvi) | |
| 312 | + || XMatchVisualInfo(xdisplay, rootscreennum, 8, StaticColor, &xvi)){ | |
| 313 | + if(xscreendepth > 8) | |
| 314 | + panic("drawterm: can't deal with colormapped depth %d screens\n", xscreendepth); | |
| 315 | + xvis = xvi.visual; | |
| 316 | + xscreendepth = 8; | |
| 317 | + } | |
| 318 | + else{ | |
| 319 | + if(xscreendepth != 8) | |
| 320 | + panic("drawterm: can't deal with depth %d screens\n", xscreendepth); | |
| 321 | + xvis = DefaultVisual(xdisplay, rootscreennum); | |
| 322 | + } | |
| 323 | + | |
| 324 | + /* | |
| 325 | + * xscreendepth is only the number of significant pixel bits, | |
| 326 | + * not the total. We need to walk the display list to find | |
| 327 | + * how many actual bits are being used per pixel. | |
| 328 | + */ | |
| 329 | + xscreenchan = 0; /* not a valid channel */ | |
| 330 | + pfmt = XListPixmapFormats(xdisplay, &n); | |
| 331 | + for(i=0; i<n; i++){ | |
| 332 | + if(pfmt[i].depth == xscreendepth){ | |
| 333 | + switch(pfmt[i].bits_per_pixel){ | |
| 334 | + case 1: /* untested */ | |
| 335 | + xscreenchan = GREY1; | |
| 336 | + break; | |
| 337 | + case 2: /* untested */ | |
| 338 | + xscreenchan = GREY2; | |
| 339 | + break; | |
| 340 | + case 4: /* untested */ | |
| 341 | + xscreenchan = GREY4; | |
| 342 | + break; | |
| 343 | + case 8: | |
| 344 | + xscreenchan = CMAP8; | |
| 345 | + break; | |
| 346 | + case 16: /* uses 16 rather than 15, empirically. */ | |
| 347 | + xscreenchan = RGB16; | |
| 348 | + break; | |
| 349 | + case 24: /* untested (impossible?) */ | |
| 350 | + xscreenchan = RGB24; | |
| 351 | + break; | |
| 352 | + case 32: | |
| 353 | + xscreenchan = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8); | |
| 354 | + break; | |
| 355 | + } | |
| 356 | + } | |
| 357 | + } | |
| 358 | + if(xscreenchan == 0) | |
| 359 | + panic("drawterm: unknown screen pixel format\n"); | |
| 360 | + | |
| 361 | + screen = DefaultScreenOfDisplay(xdisplay); | |
| 362 | + xcmap = DefaultColormapOfScreen(screen); | |
| 363 | + | |
| 364 | + if(xvis->class != StaticColor){ | |
| 365 | + graphicscmap(map); | |
| 366 | + initmap(rootwin); | |
| 367 | + } | |
| 368 | + | |
| 369 | + if((modmap = XGetModifierMapping(xdisplay))) | |
| 370 | + keypermod = modmap->max_keypermod; | |
| 371 | + | |
| 372 | + r.min = ZP; | |
| 373 | + r.max.x = WidthOfScreen(screen); | |
| 374 | + r.max.y = HeightOfScreen(screen); | |
| 375 | + | |
| 376 | + md = mallocz(sizeof(Memdata), 1); | |
| 377 | + | |
| 378 | + xsize = Dx(r)*3/4; | |
| 379 | + ysize = Dy(r)*3/4; | |
| 380 | + | |
| 381 | + attrs.colormap = xcmap; | |
| 382 | + attrs.background_pixel = 0; | |
| 383 | + attrs.border_pixel = 0; | |
| 384 | + /* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */ | |
| 385 | + xdrawable = XCreateWindow(xdisplay, rootwin, 0, 0, xsize, ysize, 0, | |
| 386 | + xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs); | |
| 387 | + | |
| 388 | + /* | |
| 389 | + * set up property as required by ICCCM | |
| 390 | + */ | |
| 391 | + name.value = (uchar*)"drawterm"; | |
| 392 | + name.encoding = XA_STRING; | |
| 393 | + name.format = 8; | |
| 394 | + name.nitems = strlen(name.value); | |
| 395 | + normalhints.flags = USSize|PMaxSize; | |
| 396 | + normalhints.max_width = Dx(r); | |
| 397 | + normalhints.max_height = Dy(r); | |
| 398 | + normalhints.width = xsize; | |
| 399 | + normalhints.height = ysize; | |
| 400 | + hints.flags = InputHint|StateHint; | |
| 401 | + hints.input = 1; | |
| 402 | + hints.initial_state = NormalState; | |
| 403 | + classhints.res_name = "drawterm"; | |
| 404 | + classhints.res_class = "Drawterm"; | |
| 405 | + argv[0] = "drawterm"; | |
| 406 | + argv[1] = nil; | |
| 407 | + XSetWMProperties(xdisplay, xdrawable, | |
| 408 | + &name, /* XA_WM_NAME property for ICCCM */ | |
| 409 | + &name, /* XA_WM_ICON_NAME */ | |
| 410 | + argv, /* XA_WM_COMMAND */ | |
| 411 | + 1, /* argc */ | |
| 412 | + &normalhints, /* XA_WM_NORMAL_HINTS */ | |
| 413 | + &hints, /* XA_WM_HINTS */ | |
| 414 | + &classhints); /* XA_WM_CLASS */ | |
| 415 | + XFlush(xdisplay); | |
| 416 | + | |
| 417 | + /* | |
| 418 | + * put the window on the screen | |
| 419 | + */ | |
| 420 | + XMapWindow(xdisplay, xdrawable); | |
| 421 | + XFlush(xdisplay); | |
| 422 | + | |
| 423 | + xscreenid = XCreatePixmap(xdisplay, xdrawable, Dx(r), Dy(r), xscreendepth); | |
| 424 | + gscreen = xallocmemimage(r, xscreenchan, xscreenid); | |
| 425 | + | |
| 426 | + xgcfill = creategc(xscreenid); | |
| 427 | + XSetFillStyle(xdisplay, xgcfill, FillSolid); | |
| 428 | + xgccopy = creategc(xscreenid); | |
| 429 | + xgcsimplesrc = creategc(xscreenid); | |
| 430 | + XSetFillStyle(xdisplay, xgcsimplesrc, FillStippled); | |
| 431 | + xgczero = creategc(xscreenid); | |
| 432 | + xgcreplsrc = creategc(xscreenid); | |
| 433 | + XSetFillStyle(xdisplay, xgcreplsrc, FillTiled); | |
| 434 | + | |
| 435 | + pmid = XCreatePixmap(xdisplay, xdrawable, 1, 1, 1); | |
| 436 | + xgcfill0 = creategc(pmid); | |
| 437 | + XSetForeground(xdisplay, xgcfill0, 0); | |
| 438 | + XSetFillStyle(xdisplay, xgcfill0, FillSolid); | |
| 439 | + xgccopy0 = creategc(pmid); | |
| 440 | + xgcsimplesrc0 = creategc(pmid); | |
| 441 | + XSetFillStyle(xdisplay, xgcsimplesrc0, FillStippled); | |
| 442 | + xgczero0 = creategc(pmid); | |
| 443 | + xgcreplsrc0 = creategc(pmid); | |
| 444 | + XSetFillStyle(xdisplay, xgcreplsrc0, FillTiled); | |
| 445 | + XFreePixmap(xdisplay, pmid); | |
| 446 | + | |
| 447 | + XSetForeground(xdisplay, xgccopy, plan9tox11[0]); | |
| 448 | + XFillRectangle(xdisplay, xscreenid, xgccopy, 0, 0, xsize, ysize); | |
| 449 | + | |
| 450 | + xkmcon = XOpenDisplay(NULL); | |
| 451 | + if(xkmcon == 0){ | |
| 452 | + disp_val = getenv("DISPLAY"); | |
| 453 | + if(disp_val == 0) | |
| 454 | + disp_val = "not set"; | |
| 455 | + iprint("drawterm: open %r, DISPLAY is %s\n", disp_val); | |
| 456 | + exit(0); | |
| 457 | + } | |
| 458 | + xsnarfcon = XOpenDisplay(NULL); | |
| 459 | + if(xsnarfcon == 0){ | |
| 460 | + disp_val = getenv("DISPLAY"); | |
| 461 | + if(disp_val == 0) | |
| 462 | + disp_val = "not set"; | |
| 463 | + iprint("drawterm: open %r, DISPLAY is %s\n", disp_val); | |
| 464 | + exit(0); | |
| 465 | + } | |
| 466 | + | |
| 467 | + clipboard = XInternAtom(xkmcon, "CLIPBOARD", False); | |
| 468 | + utf8string = XInternAtom(xkmcon, "UTF8_STRING", False); | |
| 469 | + targets = XInternAtom(xkmcon, "TARGETS", False); | |
| 470 | + text = XInternAtom(xkmcon, "TEXT", False); | |
| 471 | + compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False); | |
| 472 | + | |
| 473 | + xblack = screen->black_pixel; | |
| 474 | + xwhite = screen->white_pixel; | |
| 475 | + return gscreen; | |
| 476 | +} | |
| 477 | + | |
| 478 | +static void | |
| 479 | +graphicscmap(XColor *map) | |
| 480 | +{ | |
| 481 | + int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7; | |
| 482 | + | |
| 483 | + for(r=0; r!=4; r++) { | |
| 484 | + for(g = 0; g != 4; g++) { | |
| 485 | + for(b = 0; b!=4; b++) { | |
| 486 | + for(v = 0; v!=4; v++) { | |
| 487 | + den=r; | |
| 488 | + if(g > den) | |
| 489 | + den=g; | |
| 490 | + if(b > den) | |
| 491 | + den=b; | |
| 492 | + /* divide check -- pick grey shades */ | |
| 493 | + if(den==0) | |
| 494 | + cr=cg=cb=v*17; | |
| 495 | + else { | |
| 496 | + num=17*(4*den+v); | |
| 497 | + cr=r*num/den; | |
| 498 | + cg=g*num/den; | |
| 499 | + cb=b*num/den; | |
| 500 | + } | |
| 501 | + idx = r*64 + v*16 + ((g*4 + b + v - r) & 15); | |
| 502 | + map[idx].red = cr*0x0101; | |
| 503 | + map[idx].green = cg*0x0101; | |
| 504 | + map[idx].blue = cb*0x0101; | |
| 505 | + map[idx].pixel = idx; | |
| 506 | + map[idx].flags = DoRed|DoGreen|DoBlue; | |
| 507 | + | |
| 508 | + v7 = v >> 1; | |
| 509 | + idx7 = r*32 + v7*16 + g*4 + b; | |
| 510 | + if((v & 1) == v7){ | |
| 511 | + map7to8[idx7][0] = idx; | |
| 512 | + if(den == 0) { /* divide check -- pick grey shades */ | |
| 513 | + cr = ((255.0/7.0)*v7)+0.5; | |
| 514 | + cg = cr; | |
| 515 | + cb = cr; | |
| 516 | + } | |
| 517 | + else { | |
| 518 | + num=17*15*(4*den+v7*2)/14; | |
| 519 | + cr=r*num/den; | |
| 520 | + cg=g*num/den; | |
| 521 | + cb=b*num/den; | |
| 522 | + } | |
| 523 | + map7[idx7].red = cr*0x0101; | |
| 524 | + map7[idx7].green = cg*0x0101; | |
| 525 | + map7[idx7].blue = cb*0x0101; | |
| 526 | + map7[idx7].pixel = idx7; | |
| 527 | + map7[idx7].flags = DoRed|DoGreen|DoBlue; | |
| 528 | + } | |
| 529 | + else | |
| 530 | + map7to8[idx7][1] = idx; | |
| 531 | + } | |
| 532 | + } | |
| 533 | + } | |
| 534 | + } | |
| 535 | +} | |
| 536 | + | |
| 537 | +/* | |
| 538 | + * Initialize and install the drawterm colormap as a private colormap for this | |
| 539 | + * application. Drawterm gets the best colors here when it has the cursor focus. | |
| 540 | + */ | |
| 541 | +static void | |
| 542 | +initmap(Window w) | |
| 543 | +{ | |
| 544 | + XColor c; | |
| 545 | + int i; | |
| 546 | + ulong p, pp; | |
| 547 | + char buf[30]; | |
| 548 | + | |
| 549 | + if(xscreendepth <= 1) | |
| 550 | + return; | |
| 551 | + | |
| 552 | + if(xscreendepth >= 24) { | |
| 553 | + /* The pixel value returned from XGetPixel needs to | |
| 554 | + * be converted to RGB so we can call rgb2cmap() | |
| 555 | + * to translate between 24 bit X and our color. Unfortunately, | |
| 556 | + * the return value appears to be display server endian | |
| 557 | + * dependant. Therefore, we run some heuristics to later | |
| 558 | + * determine how to mask the int value correctly. | |
| 559 | + * Yeah, I know we can look at xvis->byte_order but | |
| 560 | + * some displays say MSB even though they run on LSB. | |
| 561 | + * Besides, this is more anal. | |
| 562 | + */ | |
| 563 | + | |
| 564 | + c = map[19]; | |
| 565 | + /* find out index into colormap for our RGB */ | |
| 566 | + if(!XAllocColor(xdisplay, xcmap, &c)) | |
| 567 | + panic("drawterm: screen-x11 can't alloc color"); | |
| 568 | + | |
| 569 | + p = c.pixel; | |
| 570 | + pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff); | |
| 571 | + if(pp!=map[19].pixel) { | |
| 572 | + /* check if endian is other way */ | |
| 573 | + pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff); | |
| 574 | + if(pp!=map[19].pixel) | |
| 575 | + panic("cannot detect x server byte order"); | |
| 576 | + switch(xscreenchan){ | |
| 577 | + case RGB24: | |
| 578 | + xscreenchan = BGR24; | |
| 579 | + break; | |
| 580 | + case XRGB32: | |
| 581 | + xscreenchan = XBGR32; | |
| 582 | + break; | |
| 583 | + default: | |
| 584 | + panic("don't know how to byteswap channel %s", | |
| 585 | + chantostr(buf, xscreenchan)); | |
| 586 | + break; | |
| 587 | + } | |
| 588 | + } | |
| 589 | + } else if(xvis->class == TrueColor || xvis->class == DirectColor) { | |
| 590 | + } else if(xvis->class == PseudoColor) { | |
| 591 | + if(xtblbit == 0){ | |
| 592 | + xcmap = XCreateColormap(xdisplay, w, xvis, AllocAll); | |
| 593 | + XStoreColors(xdisplay, xcmap, map, 256); | |
| 594 | + for(i = 0; i < 256; i++) { | |
| 595 | + plan9tox11[i] = i; | |
| 596 | + x11toplan9[i] = i; | |
| 597 | + } | |
| 598 | + } | |
| 599 | + else { | |
| 600 | + for(i = 0; i < 128; i++) { | |
| 601 | + c = map7[i]; | |
| 602 | + if(!XAllocColor(xdisplay, xcmap, &c)) { | |
| 603 | + iprint("drawterm: can't alloc colors in default map, don't use -7\n"); | |
| 604 | + exit(0); | |
| 605 | + } | |
| 606 | + plan9tox11[map7to8[i][0]] = c.pixel; | |
| 607 | + plan9tox11[map7to8[i][1]] = c.pixel; | |
| 608 | + x11toplan9[c.pixel] = map7to8[i][0]; | |
| 609 | + } | |
| 610 | + } | |
| 611 | + } | |
| 612 | + else | |
| 613 | + panic("drawterm: unsupported visual class %d\n", xvis->class); | |
| 614 | +} | |
| 615 | + | |
| 616 | +static void | |
| 617 | +xdestroy(XEvent *e) | |
| 618 | +{ | |
| 619 | + XDestroyWindowEvent *xe; | |
| 620 | + if(e->type != DestroyNotify) | |
| 621 | + return; | |
| 622 | + xe = (XDestroyWindowEvent*)e; | |
| 623 | + if(xe->window == xdrawable) | |
| 624 | + exit(0); | |
| 625 | +} | |
| 626 | + | |
| 627 | +static void | |
| 628 | +xselection(XEvent *e) | |
| 629 | +{ | |
| 630 | + XSelectionRequestEvent *xre; | |
| 631 | + XSelectionEvent *xe; | |
| 632 | +} | |
| 633 | + | |
| 634 | +static void | |
| 635 | +xmapping(XEvent *e) | |
| 636 | +{ | |
| 637 | + XMappingEvent *xe; | |
| 638 | + | |
| 639 | + if(e->type != MappingNotify) | |
| 640 | + return; | |
| 641 | + xe = (XMappingEvent*)e; | |
| 642 | + if(modmap) | |
| 643 | + XFreeModifiermap(modmap); | |
| 644 | + modmap = XGetModifierMapping(xe->display); | |
| 645 | + if(modmap) | |
| 646 | + keypermod = modmap->max_keypermod; | |
| 647 | +} | |
| 648 | + | |
| 649 | + | |
| 650 | +/* | |
| 651 | + * Disable generation of GraphicsExpose/NoExpose events in the GC. | |
| 652 | + */ | |
| 653 | +static GC | |
| 654 | +creategc(Drawable d) | |
| 655 | +{ | |
| 656 | + XGCValues gcv; | |
| 657 | + | |
| 658 | + gcv.function = GXcopy; | |
| 659 | + gcv.graphics_exposures = False; | |
| 660 | + return XCreateGC(xdisplay, d, GCFunction|GCGraphicsExposures, &gcv); | |
| 661 | +} | |
| 662 | + | |
| 663 | +static void | |
| 664 | +xexpose(XEvent *e) | |
| 665 | +{ | |
| 666 | + IRectangle r; | |
| 667 | + XExposeEvent *xe; | |
| 668 | + | |
| 669 | + if(e->type != Expose) | |
| 670 | + return; | |
| 671 | + xe = (XExposeEvent*)e; | |
| 672 | + r.min.x = xe->x; | |
| 673 | + r.min.y = xe->y; | |
| 674 | + r.max.x = xe->x + xe->width; | |
| 675 | + r.max.y = xe->y + xe->height; | |
| 676 | + drawflushr(r); | |
| 677 | +} | |
| 678 | + | |
| 679 | +static void | |
| 680 | +xkeyboard(XEvent *e) | |
| 681 | +{ | |
| 682 | + KeySym k; | |
| 683 | + unsigned int md; | |
| 684 | + | |
| 685 | + /* | |
| 686 | + * I tried using XtGetActionKeysym, but it didn't seem to | |
| 687 | + * do case conversion properly | |
| 688 | + * (at least, with Xterminal servers and R4 intrinsics) | |
| 689 | + */ | |
| 690 | + if(e->xany.type != KeyPress) | |
| 691 | + return; | |
| 692 | + | |
| 693 | + | |
| 694 | + XLookupString(e,NULL,0,&k,NULL); | |
| 695 | + | |
| 696 | + if(k == XK_Multi_key || k == NoSymbol) | |
| 697 | + return; | |
| 698 | + if(k&0xFF00){ | |
| 699 | + switch(k){ | |
| 700 | + case XK_BackSpace: | |
| 701 | + case XK_Tab: | |
| 702 | + case XK_Escape: | |
| 703 | + case XK_Delete: | |
| 704 | + case XK_KP_0: | |
| 705 | + case XK_KP_1: | |
| 706 | + case XK_KP_2: | |
| 707 | + case XK_KP_3: | |
| 708 | + case XK_KP_4: | |
| 709 | + case XK_KP_5: | |
| 710 | + case XK_KP_6: | |
| 711 | + case XK_KP_7: | |
| 712 | + case XK_KP_8: | |
| 713 | + case XK_KP_9: | |
| 714 | + case XK_KP_Divide: | |
| 715 | + case XK_KP_Multiply: | |
| 716 | + case XK_KP_Subtract: | |
| 717 | + case XK_KP_Add: | |
| 718 | + case XK_KP_Decimal: | |
| 719 | + k &= 0x7F; | |
| 720 | + break; | |
| 721 | + case XK_Linefeed: | |
| 722 | + k = '\r'; | |
| 723 | + break; | |
| 724 | + case XK_KP_Space: | |
| 725 | + k = ' '; | |
| 726 | + break; | |
| 727 | + case XK_Home: | |
| 728 | + case XK_KP_Home: | |
| 729 | + k = Khome; | |
| 730 | + break; | |
| 731 | + case XK_Left: | |
| 732 | + case XK_KP_Left: | |
| 733 | + k = Kleft; | |
| 734 | + break; | |
| 735 | + case XK_Up: | |
| 736 | + case XK_KP_Up: | |
| 737 | + k = Kup; | |
| 738 | + break; | |
| 739 | + case XK_Down: | |
| 740 | + case XK_KP_Down: | |
| 741 | + k = Kdown; | |
| 742 | + break; | |
| 743 | + case XK_Right: | |
| 744 | + case XK_KP_Right: | |
| 745 | + k = Kright; | |
| 746 | + break; | |
| 747 | + case XK_Page_Down: | |
| 748 | + case XK_KP_Page_Down: | |
| 749 | + k = Kpgdown; | |
| 750 | + break; | |
| 751 | + case XK_End: | |
| 752 | + case XK_KP_End: | |
| 753 | + k = Kend; | |
| 754 | + break; | |
| 755 | + case XK_Page_Up: | |
| 756 | + case XK_KP_Page_Up: | |
| 757 | + k = Kpgup; | |
| 758 | + break; | |
| 759 | + case XK_Insert: | |
| 760 | + case XK_KP_Insert: | |
| 761 | + k = Kins; | |
| 762 | + break; | |
| 763 | + case XK_KP_Enter: | |
| 764 | + case XK_Return: | |
| 765 | + k = '\n'; | |
| 766 | + break; | |
| 767 | + case XK_Alt_L: | |
| 768 | + case XK_Alt_R: | |
| 769 | + k = Kalt; | |
| 770 | + break; | |
| 771 | + case XK_Shift_L: | |
| 772 | + case XK_Shift_R: | |
| 773 | + case XK_Control_L: | |
| 774 | + case XK_Control_R: | |
| 775 | + case XK_Caps_Lock: | |
| 776 | + case XK_Shift_Lock: | |
| 777 | + | |
| 778 | + case XK_Meta_L: | |
| 779 | + case XK_Meta_R: | |
| 780 | + case XK_Super_L: | |
| 781 | + case XK_Super_R: | |
| 782 | + case XK_Hyper_L: | |
| 783 | + case XK_Hyper_R: | |
| 784 | + return; | |
| 785 | + default: /* not ISO-1 or tty control */ | |
| 786 | + if(k>0xff) { | |
| 787 | + k = keysym2ucs(k); /* supplied by X */ | |
| 788 | + if(k == -1) return; | |
| 789 | + } | |
| 790 | + } | |
| 791 | + } | |
| 792 | + | |
| 793 | + /* Compensate for servers that call a minus a hyphen */ | |
| 794 | + if(k == XK_hyphen) | |
| 795 | + k = XK_minus; | |
| 796 | + /* Do control mapping ourselves if translator doesn't */ | |
| 797 | + if(e->xkey.state&ControlMask) | |
| 798 | + k &= 0x9f; | |
| 799 | + if(k == NoSymbol) { | |
| 800 | + return; | |
| 801 | + } | |
| 802 | + | |
| 803 | + kbdputc(kbdq, k); | |
| 804 | +} | |
| 805 | + | |
| 806 | +static void | |
| 807 | +xmouse(XEvent *e) | |
| 808 | +{ | |
| 809 | + Mousestate ms; | |
| 810 | + int i, s; | |
| 811 | + XButtonEvent *be; | |
| 812 | + XMotionEvent *me; | |
| 813 | + | |
| 814 | + switch(e->type){ | |
| 815 | + case ButtonPress: | |
| 816 | + be = (XButtonEvent *)e; | |
| 817 | + ms.xy.x = be->x; | |
| 818 | + ms.xy.y = be->y; | |
| 819 | + s = be->state; | |
| 820 | + ms.msec = be->time; | |
| 821 | + switch(be->button){ | |
| 822 | + case 1: | |
| 823 | + s |= Button1Mask; | |
| 824 | + break; | |
| 825 | + case 2: | |
| 826 | + s |= Button2Mask; | |
| 827 | + break; | |
| 828 | + case 3: | |
| 829 | + s |= Button3Mask; | |
| 830 | + break; | |
| 831 | + case 4: | |
| 832 | + s |= Button4Mask; | |
| 833 | + break; | |
| 834 | + case 5: | |
| 835 | + s |= Button5Mask; | |
| 836 | + break; | |
| 837 | + } | |
| 838 | + break; | |
| 839 | + case ButtonRelease: | |
| 840 | + be = (XButtonEvent *)e; | |
| 841 | + ms.xy.x = be->x; | |
| 842 | + ms.xy.y = be->y; | |
| 843 | + ms.msec = be->time; | |
| 844 | + s = be->state; | |
| 845 | + switch(be->button){ | |
| 846 | + case 1: | |
| 847 | + s &= ~Button1Mask; | |
| 848 | + break; | |
| 849 | + case 2: | |
| 850 | + s &= ~Button2Mask; | |
| 851 | + break; | |
| 852 | + case 3: | |
| 853 | + s &= ~Button3Mask; | |
| 854 | + break; | |
| 855 | + case 4: | |
| 856 | + s &= ~Button4Mask; | |
| 857 | + break; | |
| 858 | + case 5: | |
| 859 | + s &= ~Button5Mask; | |
| 860 | + break; | |
| 861 | + } | |
| 862 | + break; | |
| 863 | + case MotionNotify: | |
| 864 | + me = (XMotionEvent *)e; | |
| 865 | + s = me->state; | |
| 866 | + ms.xy.x = me->x; | |
| 867 | + ms.xy.y = me->y; | |
| 868 | + ms.msec = me->time; | |
| 869 | + break; | |
| 870 | + default: | |
| 871 | + return; | |
| 872 | + } | |
| 873 | + | |
| 874 | + ms.buttons = 0; | |
| 875 | + if(s & Button1Mask) | |
| 876 | + ms.buttons |= 1; | |
| 877 | + if(s & Button2Mask) | |
| 878 | + ms.buttons |= 2; | |
| 879 | + if(s & Button3Mask) | |
| 880 | + ms.buttons |= 4; | |
| 881 | + if(s & Button4Mask) | |
| 882 | + ms.buttons |= 8; | |
| 883 | + if(s & Button5Mask) | |
| 884 | + ms.buttons |= 16; | |
| 885 | + | |
| 886 | + lock(&mouse.lk); | |
| 887 | + i = mouse.wi; | |
| 888 | + if(mousequeue) { | |
| 889 | + if(i == mouse.ri || mouse.lastb != ms.buttons || mouse.trans) { | |
| 890 | + mouse.wi = (i+1)%Mousequeue; | |
| 891 | + if(mouse.wi == mouse.ri) | |
| 892 | + mouse.ri = (mouse.ri+1)%Mousequeue; | |
| 893 | + mouse.trans = mouse.lastb != ms.buttons; | |
| 894 | + } else { | |
| 895 | + i = (i-1+Mousequeue)%Mousequeue; | |
| 896 | + } | |
| 897 | + } else { | |
| 898 | + mouse.wi = (i+1)%Mousequeue; | |
| 899 | + mouse.ri = i; | |
| 900 | + } | |
| 901 | + mouse.queue[i] = ms; | |
| 902 | + mouse.lastb = ms.buttons; | |
| 903 | + unlock(&mouse.lk); | |
| 904 | + wakeup(&mouse.r); | |
| 905 | +} | |
| 906 | + | |
| 907 | +void | |
| 908 | +getcolor(ulong i, ulong *r, ulong *g, ulong *b) | |
| 909 | +{ | |
| 910 | + ulong v; | |
| 911 | + | |
| 912 | + v = cmap2rgb(i); | |
| 913 | + *r = (v>>16)&0xFF; | |
| 914 | + *g = (v>>8)&0xFF; | |
| 915 | + *b = v&0xFF; | |
| 916 | +} | |
| 917 | + | |
| 918 | +void | |
| 919 | +setcolor(ulong i, ulong r, ulong g, ulong b) | |
| 920 | +{ | |
| 921 | + /* no-op */ | |
| 922 | +} | |
| 923 | + | |
| 924 | +typedef struct Clip Clip; | |
| 925 | +struct Clip | |
| 926 | +{ | |
| 927 | + char buf[SnarfSize]; | |
| 928 | + ulong n; | |
| 929 | + int want, have; | |
| 930 | + QLock lk; | |
| 931 | + Rendez vous; | |
| 932 | +}; | |
| 933 | + | |
| 934 | +Clip clip; | |
| 935 | + | |
| 936 | +enum { | |
| 937 | + Chunk = 2048 | |
| 938 | +}; | |
| 939 | + | |
| 940 | +static void | |
| 941 | +xselect(XEvent *e) | |
| 942 | +{ | |
| 943 | + XSelectionRequestEvent *q; | |
| 944 | + XEvent r; | |
| 945 | + Atom a[4]; | |
| 946 | + char *name; | |
| 947 | + | |
| 948 | + | |
| 949 | + if(e->type != SelectionRequest) | |
| 950 | + return; | |
| 951 | + | |
| 952 | + /* | |
| 953 | + * The lock is around the whole routine because we use the | |
| 954 | + * lock to make sure two people aren't sending on xkmcon | |
| 955 | + * at once. | |
| 956 | + */ | |
| 957 | + q = (XSelectionRequestEvent*)e; | |
| 958 | + | |
| 959 | + r.xselection.property = q->property; | |
| 960 | + if(q->target == targets) { | |
| 961 | + a[0] = XA_STRING; | |
| 962 | + a[1] = utf8string; | |
| 963 | + a[2] = text; | |
| 964 | + a[3] = compoundtext; | |
| 965 | + | |
| 966 | + XChangeProperty(xkmcon, q->requestor, q->property, q->target, | |
| 967 | + 8, PropModeReplace, (uchar*)a, sizeof a); | |
| 968 | + }else if(q->target == XA_STRING || q->target == utf8string || q->target == text || q->target == compoundtext){ | |
| 969 | + qlock(&clip.lk); | |
| 970 | + XChangeProperty(xkmcon, q->requestor, q->property, q->target, 8, | |
| 971 | + PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)); | |
| 972 | + qunlock(&clip.lk); | |
| 973 | + }else { | |
| 974 | + name = XGetAtomName(xkmcon, q->target); | |
| 975 | + if(strcmp(name, "TIMESTAMP") != 0) | |
| 976 | + fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)q->target); | |
| 977 | + r.xselection.property = None; | |
| 978 | + } | |
| 979 | + | |
| 980 | + r.xselection.type = SelectionNotify; | |
| 981 | + r.xselection.display = q->display; | |
| 982 | + r.xselection.requestor = q->requestor; | |
| 983 | + r.xselection.selection = q->selection; | |
| 984 | + r.xselection.target = q->target; | |
| 985 | + r.xselection.time = q->time; | |
| 986 | + XSendEvent(xkmcon, q->requestor, False, 0, &r); | |
| 987 | + XFlush(xkmcon); | |
| 988 | +} | |
| 989 | + | |
| 990 | +int | |
| 991 | +haveclip(void *a) | |
| 992 | +{ | |
| 993 | + return clip.want == clip.have; | |
| 994 | +} | |
| 995 | + | |
| 996 | +#undef long /* sic */ | |
| 997 | +char* | |
| 998 | +clipread(void) | |
| 999 | +{ | |
| 1000 | + Window w; | |
| 1001 | + XEvent e; | |
| 1002 | + Atom type; | |
| 1003 | + unsigned long len, lleft, left, dummy; | |
| 1004 | + int i, fmt, res; | |
| 1005 | + uchar *data; | |
| 1006 | + | |
| 1007 | + qlock(&clip.lk); | |
| 1008 | + w = XGetSelectionOwner(xsnarfcon, XA_PRIMARY); | |
| 1009 | + if(w == xdrawable) | |
| 1010 | + data = (uchar*)strdup(clip.buf); | |
| 1011 | + else if(w == None) | |
| 1012 | + data = nil; | |
| 1013 | + else { | |
| 1014 | + /* | |
| 1015 | + * we're supposed to get a notification, but we seem not to, | |
| 1016 | + * so let's just watch and see when the buffer stabilizes. | |
| 1017 | + * if you know how to fix this, mail rsc@plan9.bell-labs.com. | |
| 1018 | + */ | |
| 1019 | + XChangeProperty(xsnarfcon, xdrawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace, | |
| 1020 | + (uchar*)"", 0); | |
| 1021 | + XConvertSelection(xsnarfcon, XA_PRIMARY, XA_STRING, None, xdrawable, CurrentTime); | |
| 1022 | + XFlush(xsnarfcon); | |
| 1023 | + for(i=0; i<30; i++){ | |
| 1024 | + osmsleep(100); | |
| 1025 | + XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, 0, 0, AnyPropertyType, | |
| 1026 | + &type, &fmt, &len, &left, &data); | |
| 1027 | + if(lleft == left && left > 0) | |
| 1028 | + break; | |
| 1029 | + lleft = left; | |
| 1030 | + } | |
| 1031 | + if(left > 0){ | |
| 1032 | + res = XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, left, 0, | |
| 1033 | + AnyPropertyType, &type, &fmt, &len, &dummy, &data); | |
| 1034 | + data = (uchar*)strdup(data); | |
| 1035 | + }else | |
| 1036 | + data = nil; | |
| 1037 | + } | |
| 1038 | + qunlock(&clip.lk); | |
| 1039 | + return (char*)data; | |
| 1040 | +} | |
| 1041 | + | |
| 1042 | +int | |
| 1043 | +clipwrite(char *buf) | |
| 1044 | +{ | |
| 1045 | + int n; | |
| 1046 | + | |
| 1047 | + n = strlen(buf); | |
| 1048 | + qlock(&clip.lk); | |
| 1049 | + if(n >= SnarfSize) | |
| 1050 | + n = SnarfSize - 1; | |
| 1051 | + memmove(clip.buf, buf, n); | |
| 1052 | + clip.buf[n] = 0; | |
| 1053 | + clip.n = n; | |
| 1054 | + /* | |
| 1055 | + * xkmcon so that we get the event in the select loop. | |
| 1056 | + * It seems to be okay to send a message and read an event | |
| 1057 | + * from a Display* at the same time. Let's hope so. | |
| 1058 | + */ | |
| 1059 | + XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime); | |
| 1060 | + XFlush(xkmcon); | |
| 1061 | + qunlock(&clip.lk); | |
| 1062 | + return n; | |
| 1063 | +} | |
| 1064 | +#define long int /* sic */ | |
| 1065 | + | |
| 1066 | +int | |
| 1067 | +atlocalconsole(void) | |
| 1068 | +{ | |
| 1069 | + char *p, *q; | |
| 1070 | + char buf[128]; | |
| 1071 | + | |
| 1072 | + p = getenv("DISPLAY"); | |
| 1073 | + if(p == nil) | |
| 1074 | + return 0; | |
| 1075 | + | |
| 1076 | + /* extract host part */ | |
| 1077 | + q = strchr(p, ':'); | |
| 1078 | + if(q == nil) | |
| 1079 | + return 0; | |
| 1080 | + *q = 0; | |
| 1081 | + | |
| 1082 | + if(strcmp(p, "") == 0) | |
| 1083 | + return 1; | |
| 1084 | + | |
| 1085 | + /* try to match against system name (i.e. for ssh) */ | |
| 1086 | + if(gethostname(buf, sizeof buf) == 0){ | |
| 1087 | + if(strcmp(p, buf) == 0) | |
| 1088 | + return 1; | |
| 1089 | + if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.') | |
| 1090 | + return 1; | |
| 1091 | + } | |
| 1092 | + | |
| 1093 | + return 0; | |
| 1094 | +} | |
| @@ -0,0 +1,60 @@ | ||
| 1 | +#define Font XXFont | |
| 2 | +#define Screen XXScreen | |
| 3 | +#define Display XXDisplay | |
| 4 | + | |
| 5 | +#include <X11/Xlib.h> | |
| 6 | +/* #include <X11/Xlibint.h> */ | |
| 7 | +#include <X11/Xatom.h> | |
| 8 | +#include <X11/Xutil.h> | |
| 9 | +#include <X11/IntrinsicP.h> | |
| 10 | +#include <X11/StringDefs.h> | |
| 11 | + | |
| 12 | +#undef Font | |
| 13 | +#undef Screen | |
| 14 | +#undef Display | |
| 15 | + | |
| 16 | +/* | |
| 17 | + * Structure pointed to by X field of Memimage | |
| 18 | + */ | |
| 19 | +typedef struct Xmem Xmem; | |
| 20 | + | |
| 21 | +enum | |
| 22 | +{ | |
| 23 | + PMundef = ~0 /* undefined pixmap id */ | |
| 24 | +}; | |
| 25 | + | |
| 26 | + | |
| 27 | +struct Xmem | |
| 28 | +{ | |
| 29 | + int pmid; /* pixmap id for screen ldepth instance */ | |
| 30 | + XImage *xi; /* local image if we currenty have the data */ | |
| 31 | + int dirty; | |
| 32 | + Rectangle dirtyr; | |
| 33 | + Rectangle r; | |
| 34 | + ulong pc; /* who wrote into xi */ | |
| 35 | +}; | |
| 36 | + | |
| 37 | +extern int xtblbit; | |
| 38 | +extern int x24bitswap; | |
| 39 | +extern int plan9tox11[]; | |
| 40 | +extern int x11toplan9[]; | |
| 41 | +extern int xscreendepth; | |
| 42 | +extern XXDisplay *xdisplay; | |
| 43 | +extern Drawable xscreenid; | |
| 44 | +extern Visual *xvis; | |
| 45 | +extern GC xgcfill, xgcfill0; | |
| 46 | +extern int xgcfillcolor, xgcfillcolor0; | |
| 47 | +extern GC xgccopy, xgccopy0; | |
| 48 | +extern GC xgczero, xgczero0; | |
| 49 | +extern int xgczeropm, xgczeropm0; | |
| 50 | +extern GC xgcsimplesrc, xgcsimplesrc0; | |
| 51 | +extern int xgcsimplecolor, xgcsimplecolor0, xgcsimplepm, xgcsimplepm0; | |
| 52 | +extern GC xgcreplsrc, xgcreplsrc0; | |
| 53 | +extern int xgcreplsrcpm, xgcreplsrcpm0, xgcreplsrctile, xgcreplsrctile0; | |
| 54 | +extern XImage* allocXdata(Memimage*, Rectangle); | |
| 55 | +extern void putXdata(Memimage*, Rectangle); | |
| 56 | +extern XImage* getXdata(Memimage*, Rectangle); | |
| 57 | +extern void freeXdata(Memimage*); | |
| 58 | +extern void dirtyXdata(Memimage*, Rectangle); | |
| 59 | +extern ulong xscreenchan; | |
| 60 | +extern void xfillcolor(Memimage*, Rectangle, ulong); | |
Binary file not shown.
| @@ -0,0 +1,144 @@ | ||
| 1 | +#pragma src "/sys/src/libauth" | |
| 2 | +#pragma lib "libauth.a" | |
| 3 | + | |
| 4 | +/* | |
| 5 | + * Interface for typical callers. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +typedef struct AuthInfo AuthInfo; | |
| 9 | +typedef struct Chalstate Chalstate; | |
| 10 | +typedef struct Chapreply Chapreply; | |
| 11 | +typedef struct MSchapreply MSchapreply; | |
| 12 | +typedef struct UserPasswd UserPasswd; | |
| 13 | +typedef struct AuthRpc AuthRpc; | |
| 14 | + | |
| 15 | +enum | |
| 16 | +{ | |
| 17 | + MAXCHLEN= 256, /* max challenge length */ | |
| 18 | + MAXNAMELEN= 256, /* maximum name length */ | |
| 19 | + MD5LEN= 16, | |
| 20 | + | |
| 21 | + ARok = 0, /* rpc return values */ | |
| 22 | + ARdone, | |
| 23 | + ARerror, | |
| 24 | + ARneedkey, | |
| 25 | + ARbadkey, | |
| 26 | + ARwritenext, | |
| 27 | + ARtoosmall, | |
| 28 | + ARtoobig, | |
| 29 | + ARrpcfailure, | |
| 30 | + ARphase, | |
| 31 | + | |
| 32 | + AuthRpcMax = 4096, | |
| 33 | +}; | |
| 34 | + | |
| 35 | +struct AuthRpc | |
| 36 | +{ | |
| 37 | + int afd; | |
| 38 | + char ibuf[AuthRpcMax]; | |
| 39 | + char obuf[AuthRpcMax]; | |
| 40 | + char *arg; | |
| 41 | + uint narg; | |
| 42 | +}; | |
| 43 | + | |
| 44 | +struct AuthInfo | |
| 45 | +{ | |
| 46 | + char *cuid; /* caller id */ | |
| 47 | + char *suid; /* server id */ | |
| 48 | + char *cap; /* capability (only valid on server side) */ | |
| 49 | + int nsecret; /* length of secret */ | |
| 50 | + uchar *secret; /* secret */ | |
| 51 | +}; | |
| 52 | + | |
| 53 | +struct Chalstate | |
| 54 | +{ | |
| 55 | + char *user; | |
| 56 | + char chal[MAXCHLEN]; | |
| 57 | + int nchal; | |
| 58 | + void *resp; | |
| 59 | + int nresp; | |
| 60 | + | |
| 61 | +/* for implementation only */ | |
| 62 | + int afd; /* to factotum */ | |
| 63 | + AuthRpc *rpc; /* to factotum */ | |
| 64 | + char userbuf[MAXNAMELEN]; /* temp space if needed */ | |
| 65 | + int userinchal; /* user was sent to obtain challenge */ | |
| 66 | +}; | |
| 67 | + | |
| 68 | +struct Chapreply /* for protocol "chap" */ | |
| 69 | +{ | |
| 70 | + uchar id; | |
| 71 | + char resp[MD5LEN]; | |
| 72 | +}; | |
| 73 | + | |
| 74 | +struct MSchapreply /* for protocol "mschap" */ | |
| 75 | +{ | |
| 76 | + char LMresp[24]; /* Lan Manager response */ | |
| 77 | + char NTresp[24]; /* NT response */ | |
| 78 | +}; | |
| 79 | + | |
| 80 | +struct UserPasswd | |
| 81 | +{ | |
| 82 | + char *user; | |
| 83 | + char *passwd; | |
| 84 | +}; | |
| 85 | + | |
| 86 | +extern int newns(char*, char*); | |
| 87 | +extern int addns(char*, char*); | |
| 88 | + | |
| 89 | +extern int noworld(char*); | |
| 90 | +extern int amount(int, char*, int, char*); | |
| 91 | + | |
| 92 | +/* these two may get generalized away -rsc */ | |
| 93 | +extern int login(char*, char*, char*); | |
| 94 | +extern int httpauth(char*, char*); | |
| 95 | + | |
| 96 | +typedef struct Attr Attr; | |
| 97 | +typedef struct String String; | |
| 98 | +enum { | |
| 99 | + AttrNameval, /* name=val -- when matching, must have name=val */ | |
| 100 | + AttrQuery, /* name? -- when matching, must be present */ | |
| 101 | + AttrDefault, /* name:=val -- when matching, if present must match INTERNAL */ | |
| 102 | +}; | |
| 103 | +struct Attr | |
| 104 | +{ | |
| 105 | + int type; | |
| 106 | + Attr *next; | |
| 107 | + char *name; | |
| 108 | + char *val; | |
| 109 | +}; | |
| 110 | + | |
| 111 | +typedef int AuthGetkey(char*); | |
| 112 | + | |
| 113 | +int _attrfmt(Fmt*); | |
| 114 | +Attr *_copyattr(Attr*); | |
| 115 | +Attr *_delattr(Attr*, char*); | |
| 116 | +Attr *_findattr(Attr*, char*); | |
| 117 | +void _freeattr(Attr*); | |
| 118 | +Attr *_mkattr(int, char*, char*, Attr*); | |
| 119 | +Attr *_parseattr(char*); | |
| 120 | +char *_strfindattr(Attr*, char*); | |
| 121 | +#pragma varargck type "A" Attr* | |
| 122 | + | |
| 123 | +extern AuthInfo* fauth_proxy(int, AuthRpc *rpc, AuthGetkey *getkey, char *params); | |
| 124 | +extern AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...); | |
| 125 | +extern int auth_getkey(char*); | |
| 126 | +extern int (*amount_getkey)(char*); | |
| 127 | +extern void auth_freeAI(AuthInfo *ai); | |
| 128 | +extern int auth_chuid(AuthInfo *ai, char *ns); | |
| 129 | +extern Chalstate *auth_challenge(char*, ...); | |
| 130 | +extern AuthInfo* auth_response(Chalstate*); | |
| 131 | +extern int auth_respond(void*, uint, char*, uint, void*, uint, AuthGetkey *getkey, char*, ...); | |
| 132 | +extern void auth_freechal(Chalstate*); | |
| 133 | +extern AuthInfo* auth_userpasswd(char *user, char *passwd); | |
| 134 | +extern UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char*, ...); | |
| 135 | +extern AuthInfo* auth_getinfo(AuthRpc *rpc); | |
| 136 | +extern AuthRpc* auth_allocrpc(int afd); | |
| 137 | +extern Attr* auth_attr(AuthRpc *rpc); | |
| 138 | +extern void auth_freerpc(AuthRpc *rpc); | |
| 139 | +extern uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int n); | |
| 140 | +extern int auth_wep(char*, char*, ...); | |
| 141 | +#pragma varargck argpos auth_proxy 3 | |
| 142 | +#pragma varargck argpos auth_challenge 1 | |
| 143 | +#pragma varargck argpos auth_respond 3 | |
| 144 | +#pragma varargck argpos auth_getuserpasswd 2 | |
| @@ -0,0 +1,166 @@ | ||
| 1 | +#pragma src "/sys/src/libauthsrv" | |
| 2 | +#pragma lib "libauthsrv.a" | |
| 3 | + | |
| 4 | +/* | |
| 5 | + * Interface for talking to authentication server. | |
| 6 | + */ | |
| 7 | +typedef struct Ticket Ticket; | |
| 8 | +typedef struct Ticketreq Ticketreq; | |
| 9 | +typedef struct Authenticator Authenticator; | |
| 10 | +typedef struct Nvrsafe Nvrsafe; | |
| 11 | +typedef struct Passwordreq Passwordreq; | |
| 12 | +typedef struct OChapreply OChapreply; | |
| 13 | +typedef struct OMSchapreply OMSchapreply; | |
| 14 | + | |
| 15 | +enum | |
| 16 | +{ | |
| 17 | + ANAMELEN= 28, /* maximum size of name in previous proto */ | |
| 18 | + AERRLEN= 64, /* maximum size of errstr in previous proto */ | |
| 19 | + DOMLEN= 48, /* length of an authentication domain name */ | |
| 20 | + DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */ | |
| 21 | + CHALLEN= 8, /* length of a plan9 sk1 challenge */ | |
| 22 | + NETCHLEN= 16, /* max network challenge length (used in AS protocol) */ | |
| 23 | + CONFIGLEN= 14, | |
| 24 | + SECRETLEN= 32, /* max length of a secret */ | |
| 25 | + | |
| 26 | + KEYDBOFF= 8, /* length of random data at the start of key file */ | |
| 27 | + OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* length of an entry in old key file */ | |
| 28 | + KEYDBLEN= OKEYDBLEN+SECRETLEN, /* length of an entry in key file */ | |
| 29 | + OMD5LEN= 16, | |
| 30 | +}; | |
| 31 | + | |
| 32 | +/* encryption numberings (anti-replay) */ | |
| 33 | +enum | |
| 34 | +{ | |
| 35 | + AuthTreq=1, /* ticket request */ | |
| 36 | + AuthChal=2, /* challenge box request */ | |
| 37 | + AuthPass=3, /* change password */ | |
| 38 | + AuthOK=4, /* fixed length reply follows */ | |
| 39 | + AuthErr=5, /* error follows */ | |
| 40 | + AuthMod=6, /* modify user */ | |
| 41 | + AuthApop=7, /* apop authentication for pop3 */ | |
| 42 | + AuthOKvar=9, /* variable length reply follows */ | |
| 43 | + AuthChap=10, /* chap authentication for ppp */ | |
| 44 | + AuthMSchap=11, /* MS chap authentication for ppp */ | |
| 45 | + AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */ | |
| 46 | + AuthHttp=13, /* http domain login */ | |
| 47 | + AuthVNC=14, /* VNC server login (deprecated) */ | |
| 48 | + | |
| 49 | + | |
| 50 | + AuthTs=64, /* ticket encrypted with server's key */ | |
| 51 | + AuthTc, /* ticket encrypted with client's key */ | |
| 52 | + AuthAs, /* server generated authenticator */ | |
| 53 | + AuthAc, /* client generated authenticator */ | |
| 54 | + AuthTp, /* ticket encrypted with client's key for password change */ | |
| 55 | + AuthHr, /* http reply */ | |
| 56 | +}; | |
| 57 | + | |
| 58 | +struct Ticketreq | |
| 59 | +{ | |
| 60 | + char type; | |
| 61 | + char authid[ANAMELEN]; /* server's encryption id */ | |
| 62 | + char authdom[DOMLEN]; /* server's authentication domain */ | |
| 63 | + char chal[CHALLEN]; /* challenge from server */ | |
| 64 | + char hostid[ANAMELEN]; /* host's encryption id */ | |
| 65 | + char uid[ANAMELEN]; /* uid of requesting user on host */ | |
| 66 | +}; | |
| 67 | +#define TICKREQLEN (3*ANAMELEN+CHALLEN+DOMLEN+1) | |
| 68 | + | |
| 69 | +struct Ticket | |
| 70 | +{ | |
| 71 | + char num; /* replay protection */ | |
| 72 | + char chal[CHALLEN]; /* server challenge */ | |
| 73 | + char cuid[ANAMELEN]; /* uid on client */ | |
| 74 | + char suid[ANAMELEN]; /* uid on server */ | |
| 75 | + char key[DESKEYLEN]; /* nonce DES key */ | |
| 76 | +}; | |
| 77 | +#define TICKETLEN (CHALLEN+2*ANAMELEN+DESKEYLEN+1) | |
| 78 | + | |
| 79 | +struct Authenticator | |
| 80 | +{ | |
| 81 | + char num; /* replay protection */ | |
| 82 | + char chal[CHALLEN]; | |
| 83 | + ulong id; /* authenticator id, ++'d with each auth */ | |
| 84 | +}; | |
| 85 | +#define AUTHENTLEN (CHALLEN+4+1) | |
| 86 | + | |
| 87 | +struct Passwordreq | |
| 88 | +{ | |
| 89 | + char num; | |
| 90 | + char old[ANAMELEN]; | |
| 91 | + char new[ANAMELEN]; | |
| 92 | + char changesecret; | |
| 93 | + char secret[SECRETLEN]; /* new secret */ | |
| 94 | +}; | |
| 95 | +#define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN) | |
| 96 | + | |
| 97 | +struct OChapreply | |
| 98 | +{ | |
| 99 | + uchar id; | |
| 100 | + char uid[ANAMELEN]; | |
| 101 | + char resp[OMD5LEN]; | |
| 102 | +}; | |
| 103 | + | |
| 104 | +struct OMSchapreply | |
| 105 | +{ | |
| 106 | + char uid[ANAMELEN]; | |
| 107 | + char LMresp[24]; /* Lan Manager response */ | |
| 108 | + char NTresp[24]; /* NT response */ | |
| 109 | +}; | |
| 110 | + | |
| 111 | +/* | |
| 112 | + * convert to/from wire format | |
| 113 | + */ | |
| 114 | +extern int convT2M(Ticket*, char*, char*); | |
| 115 | +extern void convM2T(char*, Ticket*, char*); | |
| 116 | +extern void convM2Tnoenc(char*, Ticket*); | |
| 117 | +extern int convA2M(Authenticator*, char*, char*); | |
| 118 | +extern void convM2A(char*, Authenticator*, char*); | |
| 119 | +extern int convTR2M(Ticketreq*, char*); | |
| 120 | +extern void convM2TR(char*, Ticketreq*); | |
| 121 | +extern int convPR2M(Passwordreq*, char*, char*); | |
| 122 | +extern void convM2PR(char*, Passwordreq*, char*); | |
| 123 | + | |
| 124 | +/* | |
| 125 | + * convert ascii password to DES key | |
| 126 | + */ | |
| 127 | +extern int opasstokey(char*, char*); | |
| 128 | +extern int passtokey(char*, char*); | |
| 129 | + | |
| 130 | +/* | |
| 131 | + * Nvram interface | |
| 132 | + */ | |
| 133 | +enum { | |
| 134 | + NVwrite = 1<<0, /* always prompt and rewrite nvram */ | |
| 135 | + NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */ | |
| 136 | +}; | |
| 137 | + | |
| 138 | +struct Nvrsafe | |
| 139 | +{ | |
| 140 | + char machkey[DESKEYLEN]; | |
| 141 | + uchar machsum; | |
| 142 | + char authkey[DESKEYLEN]; | |
| 143 | + uchar authsum; | |
| 144 | + char config[CONFIGLEN]; | |
| 145 | + uchar configsum; | |
| 146 | + char authid[ANAMELEN]; | |
| 147 | + uchar authidsum; | |
| 148 | + char authdom[DOMLEN]; | |
| 149 | + uchar authdomsum; | |
| 150 | +}; | |
| 151 | + | |
| 152 | +extern uchar nvcsum(void*, int); | |
| 153 | +extern int readnvram(Nvrsafe*, int); | |
| 154 | + | |
| 155 | +/* | |
| 156 | + * call up auth server | |
| 157 | + */ | |
| 158 | +extern int authdial(char *netroot, char *authdom); | |
| 159 | + | |
| 160 | +/* | |
| 161 | + * exchange messages with auth server | |
| 162 | + */ | |
| 163 | +extern int _asgetticket(int, char*, char*); | |
| 164 | +extern int _asrdresp(int, char*, int); | |
| 165 | +extern int sslnegotiate(int, Ticket*, char**, char**); | |
| 166 | +extern int srvsslnegotiate(int, Ticket*, char**, char**); | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +struct Cursor | |
| 2 | +{ | |
| 3 | + Point offset; | |
| 4 | + uchar clr[2*16]; | |
| 5 | + uchar set[2*16]; | |
| 6 | +}; | |
| @@ -0,0 +1,519 @@ | ||
| 1 | +#pragma src "/sys/src/libdraw" | |
| 2 | +#pragma lib "libdraw.a" | |
| 3 | + | |
| 4 | +typedef struct Cachefont Cachefont; | |
| 5 | +typedef struct Cacheinfo Cacheinfo; | |
| 6 | +typedef struct Cachesubf Cachesubf; | |
| 7 | +typedef struct Display Display; | |
| 8 | +typedef struct Font Font; | |
| 9 | +typedef struct Fontchar Fontchar; | |
| 10 | +typedef struct Image Image; | |
| 11 | +typedef struct Mouse Mouse; | |
| 12 | +typedef struct Point Point; | |
| 13 | +typedef struct Rectangle Rectangle; | |
| 14 | +typedef struct RGB RGB; | |
| 15 | +typedef struct Screen Screen; | |
| 16 | +typedef struct Subfont Subfont; | |
| 17 | + | |
| 18 | +#pragma varargck type "R" Rectangle | |
| 19 | +#pragma varargck type "P" Point | |
| 20 | +extern int Rfmt(Fmt*); | |
| 21 | +extern int Pfmt(Fmt*); | |
| 22 | + | |
| 23 | +enum | |
| 24 | +{ | |
| 25 | + DOpaque = 0xFFFFFFFF, | |
| 26 | + DTransparent = 0x00000000, /* only useful for allocimage, memfillcolor */ | |
| 27 | + DBlack = 0x000000FF, | |
| 28 | + DWhite = 0xFFFFFFFF, | |
| 29 | + DRed = 0xFF0000FF, | |
| 30 | + DGreen = 0x00FF00FF, | |
| 31 | + DBlue = 0x0000FFFF, | |
| 32 | + DCyan = 0x00FFFFFF, | |
| 33 | + DMagenta = 0xFF00FFFF, | |
| 34 | + DYellow = 0xFFFF00FF, | |
| 35 | + DPaleyellow = 0xFFFFAAFF, | |
| 36 | + DDarkyellow = 0xEEEE9EFF, | |
| 37 | + DDarkgreen = 0x448844FF, | |
| 38 | + DPalegreen = 0xAAFFAAFF, | |
| 39 | + DMedgreen = 0x88CC88FF, | |
| 40 | + DDarkblue = 0x000055FF, | |
| 41 | + DPalebluegreen= 0xAAFFFFFF, | |
| 42 | + DPaleblue = 0x0000BBFF, | |
| 43 | + DBluegreen = 0x008888FF, | |
| 44 | + DGreygreen = 0x55AAAAFF, | |
| 45 | + DPalegreygreen = 0x9EEEEEFF, | |
| 46 | + DYellowgreen = 0x99994CFF, | |
| 47 | + DMedblue = 0x000099FF, | |
| 48 | + DGreyblue = 0x005DBBFF, | |
| 49 | + DPalegreyblue = 0x4993DDFF, | |
| 50 | + DPurpleblue = 0x8888CCFF, | |
| 51 | + | |
| 52 | + DNotacolor = 0xFFFFFF00, | |
| 53 | + DNofill = DNotacolor, | |
| 54 | + | |
| 55 | +}; | |
| 56 | + | |
| 57 | +enum | |
| 58 | +{ | |
| 59 | + Displaybufsize = 8000, | |
| 60 | + ICOSSCALE = 1024, | |
| 61 | + Borderwidth = 4, | |
| 62 | +}; | |
| 63 | + | |
| 64 | +enum | |
| 65 | +{ | |
| 66 | + /* refresh methods */ | |
| 67 | + Refbackup = 0, | |
| 68 | + Refnone = 1, | |
| 69 | + Refmesg = 2 | |
| 70 | +}; | |
| 71 | +#define NOREFRESH ((void*)-1) | |
| 72 | + | |
| 73 | +enum | |
| 74 | +{ | |
| 75 | + /* line ends */ | |
| 76 | + Endsquare = 0, | |
| 77 | + Enddisc = 1, | |
| 78 | + Endarrow = 2, | |
| 79 | + Endmask = 0x1F | |
| 80 | +}; | |
| 81 | + | |
| 82 | +#define ARROW(a, b, c) (Endarrow|((a)<<5)|((b)<<14)|((c)<<23)) | |
| 83 | + | |
| 84 | +typedef enum | |
| 85 | +{ | |
| 86 | + /* Porter-Duff compositing operators */ | |
| 87 | + Clear = 0, | |
| 88 | + | |
| 89 | + SinD = 8, | |
| 90 | + DinS = 4, | |
| 91 | + SoutD = 2, | |
| 92 | + DoutS = 1, | |
| 93 | + | |
| 94 | + S = SinD|SoutD, | |
| 95 | + SoverD = SinD|SoutD|DoutS, | |
| 96 | + SatopD = SinD|DoutS, | |
| 97 | + SxorD = SoutD|DoutS, | |
| 98 | + | |
| 99 | + D = DinS|DoutS, | |
| 100 | + DoverS = DinS|DoutS|SoutD, | |
| 101 | + DatopS = DinS|SoutD, | |
| 102 | + DxorS = DoutS|SoutD, /* == SxorD */ | |
| 103 | + | |
| 104 | + Ncomp = 12, | |
| 105 | +} Drawop; | |
| 106 | + | |
| 107 | +/* | |
| 108 | + * image channel descriptors | |
| 109 | + */ | |
| 110 | +enum { | |
| 111 | + CRed = 0, | |
| 112 | + CGreen, | |
| 113 | + CBlue, | |
| 114 | + CGrey, | |
| 115 | + CAlpha, | |
| 116 | + CMap, | |
| 117 | + CIgnore, | |
| 118 | + NChan, | |
| 119 | +}; | |
| 120 | + | |
| 121 | +#define __DC(type, nbits) ((((type)&15)<<4)|((nbits)&15)) | |
| 122 | +#define CHAN1(a,b) __DC(a,b) | |
| 123 | +#define CHAN2(a,b,c,d) (CHAN1((a),(b))<<8|__DC((c),(d))) | |
| 124 | +#define CHAN3(a,b,c,d,e,f) (CHAN2((a),(b),(c),(d))<<8|__DC((e),(f))) | |
| 125 | +#define CHAN4(a,b,c,d,e,f,g,h) (CHAN3((a),(b),(c),(d),(e),(f))<<8|__DC((g),(h))) | |
| 126 | + | |
| 127 | +#define NBITS(c) ((c)&15) | |
| 128 | +#define TYPE(c) (((c)>>4)&15) | |
| 129 | + | |
| 130 | +enum { | |
| 131 | + GREY1 = CHAN1(CGrey, 1), | |
| 132 | + GREY2 = CHAN1(CGrey, 2), | |
| 133 | + GREY4 = CHAN1(CGrey, 4), | |
| 134 | + GREY8 = CHAN1(CGrey, 8), | |
| 135 | + CMAP8 = CHAN1(CMap, 8), | |
| 136 | + RGB15 = CHAN4(CIgnore, 1, CRed, 5, CGreen, 5, CBlue, 5), | |
| 137 | + RGB16 = CHAN3(CRed, 5, CGreen, 6, CBlue, 5), | |
| 138 | + RGB24 = CHAN3(CRed, 8, CGreen, 8, CBlue, 8), | |
| 139 | + BGR24 = CHAN3(CBlue, 8, CGreen, 8, CRed, 8), | |
| 140 | + RGBA32 = CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8), | |
| 141 | + ARGB32 = CHAN4(CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8), /* stupid VGAs */ | |
| 142 | + XRGB32 = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8), | |
| 143 | + XBGR32 = CHAN4(CIgnore, 8, CBlue, 8, CGreen, 8, CRed, 8), | |
| 144 | +}; | |
| 145 | + | |
| 146 | +extern char* chantostr(char*, ulong); | |
| 147 | +extern ulong strtochan(char*); | |
| 148 | +extern int chantodepth(ulong); | |
| 149 | + | |
| 150 | +struct Point | |
| 151 | +{ | |
| 152 | + int x; | |
| 153 | + int y; | |
| 154 | +}; | |
| 155 | + | |
| 156 | +struct Rectangle | |
| 157 | +{ | |
| 158 | + Point min; | |
| 159 | + Point max; | |
| 160 | +}; | |
| 161 | + | |
| 162 | +typedef void (*Reffn)(Image*, Rectangle, void*); | |
| 163 | + | |
| 164 | +struct Screen | |
| 165 | +{ | |
| 166 | + Display *display; /* display holding data */ | |
| 167 | + int id; /* id of system-held Screen */ | |
| 168 | + Image *image; /* unused; for reference only */ | |
| 169 | + Image *fill; /* color to paint behind windows */ | |
| 170 | +}; | |
| 171 | + | |
| 172 | +struct Display | |
| 173 | +{ | |
| 174 | + QLock qlock; | |
| 175 | + int locking; /*program is using lockdisplay */ | |
| 176 | + int dirno; | |
| 177 | + int fd; | |
| 178 | + int reffd; | |
| 179 | + int ctlfd; | |
| 180 | + int imageid; | |
| 181 | + int local; | |
| 182 | + void (*error)(Display*, char*); | |
| 183 | + char *devdir; | |
| 184 | + char *windir; | |
| 185 | + char oldlabel[64]; | |
| 186 | + ulong dataqid; | |
| 187 | + Image *white; | |
| 188 | + Image *black; | |
| 189 | + Image *opaque; | |
| 190 | + Image *transparent; | |
| 191 | + Image *image; | |
| 192 | + uchar *buf; | |
| 193 | + int bufsize; | |
| 194 | + uchar *bufp; | |
| 195 | + Font *defaultfont; | |
| 196 | + Subfont *defaultsubfont; | |
| 197 | + Image *windows; | |
| 198 | + Image *screenimage; | |
| 199 | + int _isnewdisplay; | |
| 200 | +}; | |
| 201 | + | |
| 202 | +struct Image | |
| 203 | +{ | |
| 204 | + Display *display; /* display holding data */ | |
| 205 | + int id; /* id of system-held Image */ | |
| 206 | + Rectangle r; /* rectangle in data area, local coords */ | |
| 207 | + Rectangle clipr; /* clipping region */ | |
| 208 | + int depth; /* number of bits per pixel */ | |
| 209 | + ulong chan; | |
| 210 | + int repl; /* flag: data replicates to tile clipr */ | |
| 211 | + Screen *screen; /* 0 if not a window */ | |
| 212 | + Image *next; /* next in list of windows */ | |
| 213 | +}; | |
| 214 | + | |
| 215 | +struct RGB | |
| 216 | +{ | |
| 217 | + ulong red; | |
| 218 | + ulong green; | |
| 219 | + ulong blue; | |
| 220 | +}; | |
| 221 | + | |
| 222 | +/* | |
| 223 | + * Subfonts | |
| 224 | + * | |
| 225 | + * given char c, Subfont *f, Fontchar *i, and Point p, one says | |
| 226 | + * i = f->info+c; | |
| 227 | + * draw(b, Rect(p.x+i->left, p.y+i->top, | |
| 228 | + * p.x+i->left+((i+1)->x-i->x), p.y+i->bottom), | |
| 229 | + * color, f->bits, Pt(i->x, i->top)); | |
| 230 | + * p.x += i->width; | |
| 231 | + * to draw characters in the specified color (itself an Image) in Image b. | |
| 232 | + */ | |
| 233 | + | |
| 234 | +struct Fontchar | |
| 235 | +{ | |
| 236 | + int x; /* left edge of bits */ | |
| 237 | + uchar top; /* first non-zero scan-line */ | |
| 238 | + uchar bottom; /* last non-zero scan-line + 1 */ | |
| 239 | + char left; /* offset of baseline */ | |
| 240 | + uchar width; /* width of baseline */ | |
| 241 | +}; | |
| 242 | + | |
| 243 | +struct Subfont | |
| 244 | +{ | |
| 245 | + char *name; | |
| 246 | + short n; /* number of chars in font */ | |
| 247 | + uchar height; /* height of image */ | |
| 248 | + char ascent; /* top of image to baseline */ | |
| 249 | + Fontchar *info; /* n+1 character descriptors */ | |
| 250 | + Image *bits; /* of font */ | |
| 251 | + int ref; | |
| 252 | +}; | |
| 253 | + | |
| 254 | +enum | |
| 255 | +{ | |
| 256 | + /* starting values */ | |
| 257 | + LOG2NFCACHE = 6, | |
| 258 | + NFCACHE = (1<<LOG2NFCACHE), /* #chars cached */ | |
| 259 | + NFLOOK = 5, /* #chars to scan in cache */ | |
| 260 | + NFSUBF = 2, /* #subfonts to cache */ | |
| 261 | + /* max value */ | |
| 262 | + MAXFCACHE = 1024+NFLOOK, /* upper limit */ | |
| 263 | + MAXSUBF = 50, /* generous upper limit */ | |
| 264 | + /* deltas */ | |
| 265 | + DSUBF = 4, | |
| 266 | + /* expiry ages */ | |
| 267 | + SUBFAGE = 10000, | |
| 268 | + CACHEAGE = 10000 | |
| 269 | +}; | |
| 270 | + | |
| 271 | +struct Cachefont | |
| 272 | +{ | |
| 273 | + Rune min; /* lowest rune value to be taken from subfont */ | |
| 274 | + Rune max; /* highest rune value+1 to be taken from subfont */ | |
| 275 | + int offset; /* position in subfont of character at min */ | |
| 276 | + char *name; /* stored in font */ | |
| 277 | + char *subfontname; /* to access subfont */ | |
| 278 | +}; | |
| 279 | + | |
| 280 | +struct Cacheinfo | |
| 281 | +{ | |
| 282 | + ushort x; /* left edge of bits */ | |
| 283 | + uchar width; /* width of baseline */ | |
| 284 | + schar left; /* offset of baseline */ | |
| 285 | + Rune value; /* value of character at this slot in cache */ | |
| 286 | + ushort age; | |
| 287 | +}; | |
| 288 | + | |
| 289 | +struct Cachesubf | |
| 290 | +{ | |
| 291 | + ulong age; /* for replacement */ | |
| 292 | + Cachefont *cf; /* font info that owns us */ | |
| 293 | + Subfont *f; /* attached subfont */ | |
| 294 | +}; | |
| 295 | + | |
| 296 | +struct Font | |
| 297 | +{ | |
| 298 | + char *name; | |
| 299 | + Display *display; | |
| 300 | + short height; /* max height of image, interline spacing */ | |
| 301 | + short ascent; /* top of image to baseline */ | |
| 302 | + short width; /* widest so far; used in caching only */ | |
| 303 | + short nsub; /* number of subfonts */ | |
| 304 | + ulong age; /* increasing counter; used for LRU */ | |
| 305 | + int maxdepth; /* maximum depth of all loaded subfonts */ | |
| 306 | + int ncache; /* size of cache */ | |
| 307 | + int nsubf; /* size of subfont list */ | |
| 308 | + Cacheinfo *cache; | |
| 309 | + Cachesubf *subf; | |
| 310 | + Cachefont **sub; /* as read from file */ | |
| 311 | + Image *cacheimage; | |
| 312 | +}; | |
| 313 | + | |
| 314 | +#define Dx(r) ((r).max.x-(r).min.x) | |
| 315 | +#define Dy(r) ((r).max.y-(r).min.y) | |
| 316 | + | |
| 317 | +/* | |
| 318 | + * Image management | |
| 319 | + */ | |
| 320 | +extern Image* _allocimage(Image*, Display*, Rectangle, ulong, int, ulong, int, int); | |
| 321 | +extern Image* allocimage(Display*, Rectangle, ulong, int, ulong); | |
| 322 | +extern uchar* bufimage(Display*, int); | |
| 323 | +extern int bytesperline(Rectangle, int); | |
| 324 | +extern void closedisplay(Display*); | |
| 325 | +extern void drawerror(Display*, char*); | |
| 326 | +extern int flushimage(Display*, int); | |
| 327 | +extern int freeimage(Image*); | |
| 328 | +extern int _freeimage1(Image*); | |
| 329 | +extern int geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int); | |
| 330 | +extern int initdraw(void(*)(Display*, char*), char*, char*); | |
| 331 | +extern int newwindow(char*); | |
| 332 | +extern Display* initdisplay(char*, char*, void(*)(Display*, char*)); | |
| 333 | +extern int loadimage(Image*, Rectangle, uchar*, int); | |
| 334 | +extern int cloadimage(Image*, Rectangle, uchar*, int); | |
| 335 | +extern int getwindow(Display*, int); | |
| 336 | +extern int gengetwindow(Display*, char*, Image**, Screen**, int); | |
| 337 | +extern Image* readimage(Display*, int, int); | |
| 338 | +extern Image* creadimage(Display*, int, int); | |
| 339 | +extern int unloadimage(Image*, Rectangle, uchar*, int); | |
| 340 | +extern int wordsperline(Rectangle, int); | |
| 341 | +extern int writeimage(int, Image*, int); | |
| 342 | +extern Image* namedimage(Display*, char*); | |
| 343 | +extern int nameimage(Image*, char*, int); | |
| 344 | +extern Image* allocimagemix(Display*, ulong, ulong); | |
| 345 | + | |
| 346 | +/* | |
| 347 | + * Colors | |
| 348 | + */ | |
| 349 | +extern void readcolmap(Display*, RGB*); | |
| 350 | +extern void writecolmap(Display*, RGB*); | |
| 351 | +extern ulong setalpha(ulong, uchar); | |
| 352 | + | |
| 353 | +/* | |
| 354 | + * Windows | |
| 355 | + */ | |
| 356 | +extern Screen* allocscreen(Image*, Image*, int); | |
| 357 | +extern Image* _allocwindow(Image*, Screen*, Rectangle, int, ulong); | |
| 358 | +extern Image* allocwindow(Screen*, Rectangle, int, ulong); | |
| 359 | +extern void bottomnwindows(Image**, int); | |
| 360 | +extern void bottomwindow(Image*); | |
| 361 | +extern int freescreen(Screen*); | |
| 362 | +extern Screen* publicscreen(Display*, int, ulong); | |
| 363 | +extern void topnwindows(Image**, int); | |
| 364 | +extern void topwindow(Image*); | |
| 365 | +extern int originwindow(Image*, Point, Point); | |
| 366 | + | |
| 367 | +/* | |
| 368 | + * Geometry | |
| 369 | + */ | |
| 370 | +extern Point Pt(int, int); | |
| 371 | +extern Rectangle Rect(int, int, int, int); | |
| 372 | +extern Rectangle Rpt(Point, Point); | |
| 373 | +extern Point addpt(Point, Point); | |
| 374 | +extern Point subpt(Point, Point); | |
| 375 | +extern Point divpt(Point, int); | |
| 376 | +extern Point mulpt(Point, int); | |
| 377 | +extern int eqpt(Point, Point); | |
| 378 | +extern int eqrect(Rectangle, Rectangle); | |
| 379 | +extern Rectangle insetrect(Rectangle, int); | |
| 380 | +extern Rectangle rectaddpt(Rectangle, Point); | |
| 381 | +extern Rectangle rectsubpt(Rectangle, Point); | |
| 382 | +extern Rectangle canonrect(Rectangle); | |
| 383 | +extern int rectXrect(Rectangle, Rectangle); | |
| 384 | +extern int rectinrect(Rectangle, Rectangle); | |
| 385 | +extern void combinerect(Rectangle*, Rectangle); | |
| 386 | +extern int rectclip(Rectangle*, Rectangle); | |
| 387 | +extern int ptinrect(Point, Rectangle); | |
| 388 | +extern void replclipr(Image*, int, Rectangle); | |
| 389 | +extern int drawreplxy(int, int, int); /* used to be drawsetxy */ | |
| 390 | +extern Point drawrepl(Rectangle, Point); | |
| 391 | +extern int rgb2cmap(int, int, int); | |
| 392 | +extern int cmap2rgb(int); | |
| 393 | +extern int cmap2rgba(int); | |
| 394 | +extern void icossin(int, int*, int*); | |
| 395 | +extern void icossin2(int, int, int*, int*); | |
| 396 | + | |
| 397 | +/* | |
| 398 | + * Graphics | |
| 399 | + */ | |
| 400 | +extern void draw(Image*, Rectangle, Image*, Image*, Point); | |
| 401 | +extern void drawop(Image*, Rectangle, Image*, Image*, Point, Drawop); | |
| 402 | +extern void gendraw(Image*, Rectangle, Image*, Point, Image*, Point); | |
| 403 | +extern void gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop); | |
| 404 | +extern void line(Image*, Point, Point, int, int, int, Image*, Point); | |
| 405 | +extern void lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop); | |
| 406 | +extern void poly(Image*, Point*, int, int, int, int, Image*, Point); | |
| 407 | +extern void polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop); | |
| 408 | +extern void fillpoly(Image*, Point*, int, int, Image*, Point); | |
| 409 | +extern void fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop); | |
| 410 | +extern Point string(Image*, Point, Image*, Point, Font*, char*); | |
| 411 | +extern Point stringop(Image*, Point, Image*, Point, Font*, char*, Drawop); | |
| 412 | +extern Point stringn(Image*, Point, Image*, Point, Font*, char*, int); | |
| 413 | +extern Point stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop); | |
| 414 | +extern Point runestring(Image*, Point, Image*, Point, Font*, Rune*); | |
| 415 | +extern Point runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop); | |
| 416 | +extern Point runestringn(Image*, Point, Image*, Point, Font*, Rune*, int); | |
| 417 | +extern Point runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop); | |
| 418 | +extern Point stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point); | |
| 419 | +extern Point stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop); | |
| 420 | +extern Point stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point); | |
| 421 | +extern Point stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop); | |
| 422 | +extern Point runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point); | |
| 423 | +extern Point runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop); | |
| 424 | +extern Point runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point); | |
| 425 | +extern Point runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop); | |
| 426 | +extern Point _string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop); | |
| 427 | +extern Point stringsubfont(Image*, Point, Image*, Subfont*, char*); | |
| 428 | +extern int bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point); | |
| 429 | +extern int bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop); | |
| 430 | +extern int bezspline(Image*, Point*, int, int, int, int, Image*, Point); | |
| 431 | +extern int bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop); | |
| 432 | +extern int bezsplinepts(Point*, int, Point**); | |
| 433 | +extern int fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point); | |
| 434 | +extern int fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop); | |
| 435 | +extern int fillbezspline(Image*, Point*, int, int, Image*, Point); | |
| 436 | +extern int fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop); | |
| 437 | +extern void ellipse(Image*, Point, int, int, int, Image*, Point); | |
| 438 | +extern void ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop); | |
| 439 | +extern void fillellipse(Image*, Point, int, int, Image*, Point); | |
| 440 | +extern void fillellipseop(Image*, Point, int, int, Image*, Point, Drawop); | |
| 441 | +extern void arc(Image*, Point, int, int, int, Image*, Point, int, int); | |
| 442 | +extern void arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop); | |
| 443 | +extern void fillarc(Image*, Point, int, int, Image*, Point, int, int); | |
| 444 | +extern void fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop); | |
| 445 | +extern void border(Image*, Rectangle, int, Image*, Point); | |
| 446 | +extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop); | |
| 447 | + | |
| 448 | +/* | |
| 449 | + * Font management | |
| 450 | + */ | |
| 451 | +extern Font* openfont(Display*, char*); | |
| 452 | +extern Font* buildfont(Display*, char*, char*); | |
| 453 | +extern void freefont(Font*); | |
| 454 | +extern Font* mkfont(Subfont*, Rune); | |
| 455 | +extern int cachechars(Font*, char**, Rune**, ushort*, int, int*, char**); | |
| 456 | +extern void agefont(Font*); | |
| 457 | +extern Subfont* allocsubfont(char*, int, int, int, Fontchar*, Image*); | |
| 458 | +extern Subfont* lookupsubfont(Display*, char*); | |
| 459 | +extern void installsubfont(char*, Subfont*); | |
| 460 | +extern void uninstallsubfont(Subfont*); | |
| 461 | +extern void freesubfont(Subfont*); | |
| 462 | +extern Subfont* readsubfont(Display*, char*, int, int); | |
| 463 | +extern Subfont* readsubfonti(Display*, char*, int, Image*, int); | |
| 464 | +extern int writesubfont(int, Subfont*); | |
| 465 | +extern void _unpackinfo(Fontchar*, uchar*, int); | |
| 466 | +extern Point stringsize(Font*, char*); | |
| 467 | +extern int stringwidth(Font*, char*); | |
| 468 | +extern int stringnwidth(Font*, char*, int); | |
| 469 | +extern Point runestringsize(Font*, Rune*); | |
| 470 | +extern int runestringwidth(Font*, Rune*); | |
| 471 | +extern int runestringnwidth(Font*, Rune*, int); | |
| 472 | +extern Point strsubfontwidth(Subfont*, char*); | |
| 473 | +extern int loadchar(Font*, Rune, Cacheinfo*, int, int, char**); | |
| 474 | +extern char* subfontname(char*, char*, int); | |
| 475 | +extern Subfont* _getsubfont(Display*, char*); | |
| 476 | +extern Subfont* getdefont(Display*); | |
| 477 | +extern void lockdisplay(Display*); | |
| 478 | +extern void unlockdisplay(Display*); | |
| 479 | +extern int drawlsetrefresh(ulong, int, void*, void*); | |
| 480 | + | |
| 481 | +/* | |
| 482 | + * Predefined | |
| 483 | + */ | |
| 484 | +extern uchar defontdata[]; | |
| 485 | +extern int sizeofdefont; | |
| 486 | +extern Point ZP; | |
| 487 | +extern Rectangle ZR; | |
| 488 | + | |
| 489 | +/* | |
| 490 | + * Set up by initdraw() | |
| 491 | + */ | |
| 492 | +extern Display *display; | |
| 493 | +extern Font *font; | |
| 494 | +/* extern Image *screen; */ | |
| 495 | +extern Screen *_screen; | |
| 496 | +extern int _cursorfd; | |
| 497 | +extern int _drawdebug; /* set to 1 to see errors from flushimage */ | |
| 498 | +extern void _setdrawop(Display*, Drawop); | |
| 499 | + | |
| 500 | +#define BGSHORT(p) (((p)[0]<<0) | ((p)[1]<<8)) | |
| 501 | +#define BGLONG(p) ((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16)) | |
| 502 | +#define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8)) | |
| 503 | +#define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16)) | |
| 504 | + | |
| 505 | +/* | |
| 506 | + * Compressed image file parameters and helper routines | |
| 507 | + */ | |
| 508 | +#define NMATCH 3 /* shortest match possible */ | |
| 509 | +#define NRUN (NMATCH+31) /* longest match possible */ | |
| 510 | +#define NMEM 1024 /* window size */ | |
| 511 | +#define NDUMP 128 /* maximum length of dump */ | |
| 512 | +#define NCBLOCK 6000 /* size of compressed blocks */ | |
| 513 | +extern void _twiddlecompressed(uchar*, int); | |
| 514 | +extern int _compblocksize(Rectangle, int); | |
| 515 | + | |
| 516 | +/* XXX backwards helps; should go */ | |
| 517 | +extern int log2[]; | |
| 518 | +extern ulong drawld2chan[]; | |
| 519 | +extern void drawsetdebug(int); | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +#if defined(linux) || defined(IRIX) || defined(SOLARIS) || defined(OSF1) || defined(__FreeBSD__) || defined(__APPLE__) | |
| 2 | +# include "unix.h" | |
| 3 | +# ifdef __APPLE__ | |
| 4 | +# define panic dt_panic | |
| 5 | +# endif | |
| 6 | +#elif defined(WINDOWS) | |
| 7 | +# include "winduhz.h" | |
| 8 | +#else | |
| 9 | +# error "Define an OS" | |
| 10 | +#endif | |
| @@ -0,0 +1,110 @@ | ||
| 1 | +#define VERSION9P "9P2000" | |
| 2 | + | |
| 3 | +#define MAXWELEM 16 | |
| 4 | + | |
| 5 | +typedef | |
| 6 | +struct Fcall | |
| 7 | +{ | |
| 8 | + uchar type; | |
| 9 | + u32int fid; | |
| 10 | + ushort tag; | |
| 11 | + u32int msize; /* Tversion, Rversion */ | |
| 12 | + char *version; /* Tversion, Rversion */ | |
| 13 | + ushort oldtag; /* Tflush */ | |
| 14 | + char *ename; /* Rerror */ | |
| 15 | + Qid qid; /* Rattach, Ropen, Rcreate */ | |
| 16 | + u32int iounit; /* Ropen, Rcreate */ | |
| 17 | + Qid aqid; /* Rauth */ | |
| 18 | + u32int afid; /* Tauth, Tattach */ | |
| 19 | + char *uname; /* Tauth, Tattach */ | |
| 20 | + char *aname; /* Tauth, Tattach */ | |
| 21 | + u32int perm; /* Tcreate */ | |
| 22 | + char *name; /* Tcreate */ | |
| 23 | + uchar mode; /* Tcreate, Topen */ | |
| 24 | + u32int newfid; /* Twalk */ | |
| 25 | + ushort nwname; /* Twalk */ | |
| 26 | + char *wname[MAXWELEM]; /* Twalk */ | |
| 27 | + ushort nwqid; /* Rwalk */ | |
| 28 | + Qid wqid[MAXWELEM]; /* Rwalk */ | |
| 29 | + vlong offset; /* Tread, Twrite */ | |
| 30 | + u32int count; /* Tread, Twrite, Rread */ | |
| 31 | + char *data; /* Twrite, Rread */ | |
| 32 | + ushort nstat; /* Twstat, Rstat */ | |
| 33 | + uchar *stat; /* Twstat, Rstat */ | |
| 34 | +} Fcall; | |
| 35 | + | |
| 36 | + | |
| 37 | +#define GBIT8(p) ((p)[0]) | |
| 38 | +#define GBIT16(p) ((p)[0]|((p)[1]<<8)) | |
| 39 | +#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) | |
| 40 | +#define GBIT64(p) ((vlong)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\ | |
| 41 | + ((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32)) | |
| 42 | + | |
| 43 | +#define PBIT8(p,v) (p)[0]=(v) | |
| 44 | +#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8 | |
| 45 | +#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24 | |
| 46 | +#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\ | |
| 47 | + (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56 | |
| 48 | + | |
| 49 | +#define BIT8SZ 1 | |
| 50 | +#define BIT16SZ 2 | |
| 51 | +#define BIT32SZ 4 | |
| 52 | +#define BIT64SZ 8 | |
| 53 | +#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ) | |
| 54 | + | |
| 55 | +/* STATFIXLEN includes leading 16-bit count */ | |
| 56 | +/* The count, however, excludes itself; total size is BIT16SZ+count */ | |
| 57 | +#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */ | |
| 58 | + | |
| 59 | +#define NOTAG (ushort)~0U /* Dummy tag */ | |
| 60 | +#define NOFID (u32int)~0U /* Dummy fid */ | |
| 61 | +#define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */ | |
| 62 | + | |
| 63 | +enum | |
| 64 | +{ | |
| 65 | + Tversion = 100, | |
| 66 | + Rversion, | |
| 67 | + Tauth = 102, | |
| 68 | + Rauth, | |
| 69 | + Tattach = 104, | |
| 70 | + Rattach, | |
| 71 | + Terror = 106, /* illegal */ | |
| 72 | + Rerror, | |
| 73 | + Tflush = 108, | |
| 74 | + Rflush, | |
| 75 | + Twalk = 110, | |
| 76 | + Rwalk, | |
| 77 | + Topen = 112, | |
| 78 | + Ropen, | |
| 79 | + Tcreate = 114, | |
| 80 | + Rcreate, | |
| 81 | + Tread = 116, | |
| 82 | + Rread, | |
| 83 | + Twrite = 118, | |
| 84 | + Rwrite, | |
| 85 | + Tclunk = 120, | |
| 86 | + Rclunk, | |
| 87 | + Tremove = 122, | |
| 88 | + Rremove, | |
| 89 | + Tstat = 124, | |
| 90 | + Rstat, | |
| 91 | + Twstat = 126, | |
| 92 | + Rwstat, | |
| 93 | + Tmax, | |
| 94 | +}; | |
| 95 | + | |
| 96 | +uint convM2S(uchar*, uint, Fcall*); | |
| 97 | +uint convS2M(Fcall*, uchar*, uint); | |
| 98 | +uint sizeS2M(Fcall*); | |
| 99 | + | |
| 100 | +int statcheck(uchar *abuf, uint nbuf); | |
| 101 | +uint convM2D(uchar*, uint, Dir*, char*); | |
| 102 | +uint convD2M(Dir*, uchar*, uint); | |
| 103 | +uint sizeD2M(Dir*); | |
| 104 | + | |
| 105 | +int fcallfmt(Fmt*); | |
| 106 | +int dirfmt(Fmt*); | |
| 107 | +int dirmodefmt(Fmt*); | |
| 108 | + | |
| 109 | +int read9pmsg(int, void*, uint); | |
| 110 | + | |
| @@ -0,0 +1,42 @@ | ||
| 1 | +#pragma src "/sys/src/libdraw" | |
| 2 | +#pragma lib "libdraw.a" | |
| 3 | + | |
| 4 | +typedef struct Keyboardctl Keyboardctl; | |
| 5 | +typedef struct Channel Channel; | |
| 6 | + | |
| 7 | +struct Keyboardctl | |
| 8 | +{ | |
| 9 | + Channel *c; /* chan(Rune)[20] */ | |
| 10 | + | |
| 11 | + char *file; | |
| 12 | + int consfd; /* to cons file */ | |
| 13 | + int ctlfd; /* to ctl file */ | |
| 14 | + int pid; /* of slave proc */ | |
| 15 | +}; | |
| 16 | + | |
| 17 | + | |
| 18 | +extern Keyboardctl* initkeyboard(char*); | |
| 19 | +extern int ctlkeyboard(Keyboardctl*, char*); | |
| 20 | +extern void closekeyboard(Keyboardctl*); | |
| 21 | + | |
| 22 | +enum { | |
| 23 | + KF= 0xF000, /* Rune: beginning of private Unicode space */ | |
| 24 | + Spec= 0xF800, | |
| 25 | + /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */ | |
| 26 | + Khome= KF|0x0D, | |
| 27 | + Kup= KF|0x0E, | |
| 28 | + Kpgup= KF|0x0F, | |
| 29 | + Kprint= KF|0x10, | |
| 30 | + Kleft= KF|0x11, | |
| 31 | + Kright= KF|0x12, | |
| 32 | + Kdown= Spec|0x00, | |
| 33 | + Kview= Spec|0x00, | |
| 34 | + Kpgdown= KF|0x13, | |
| 35 | + Kins= KF|0x14, | |
| 36 | + Kend= KF|0x18, | |
| 37 | + | |
| 38 | + Kalt= KF|0x15, | |
| 39 | + Kshift= KF|0x16, | |
| 40 | + Kctl= KF|0x17, | |
| 41 | +}; | |
| 42 | + | |
| @@ -0,0 +1,246 @@ | ||
| 1 | +/* avoid name conflicts */ | |
| 2 | +#define accept pm_accept | |
| 3 | +#define listen pm_listen | |
| 4 | +#define sleep ksleep | |
| 5 | +#define wakeup kwakeup | |
| 6 | +#define strtod libstrtod | |
| 7 | +#define pow10 libpow10 | |
| 8 | + | |
| 9 | +/* conflicts on some os's */ | |
| 10 | +#define encrypt libencrypt | |
| 11 | +#define decrypt libdecrypt | |
| 12 | +#define oserror liboserror | |
| 13 | +#define clone libclone | |
| 14 | +#define atexit libatexit | |
| 15 | +#define log2 liblog2 | |
| 16 | +#define log liblog | |
| 17 | +#define reboot libreboot | |
| 18 | +#define srand dtsrand | |
| 19 | +#define rand dtrand | |
| 20 | +#define nrand dtnrand | |
| 21 | +#define lrand dtlrand | |
| 22 | +#define lnrand dtlnrand | |
| 23 | +#undef timeradd | |
| 24 | +#define timeradd xtimeradd | |
| 25 | + | |
| 26 | + | |
| 27 | +#define nil ((void*)0) | |
| 28 | + | |
| 29 | +typedef unsigned char p9_uchar; | |
| 30 | +typedef unsigned int p9_uint; | |
| 31 | +typedef unsigned int p9_ulong; | |
| 32 | +typedef int p9_long; | |
| 33 | +typedef signed char p9_schar; | |
| 34 | +typedef unsigned short p9_ushort; | |
| 35 | +typedef unsigned short Rune; | |
| 36 | +typedef unsigned int p9_u32int; | |
| 37 | +typedef p9_u32int mpdigit; | |
| 38 | + | |
| 39 | +/* make sure we don't conflict with predefined types */ | |
| 40 | +#define schar p9_schar | |
| 41 | +#define uchar p9_uchar | |
| 42 | +#define ushort p9_ushort | |
| 43 | +#define uint p9_uint | |
| 44 | +#define u32int p9_u32int | |
| 45 | + | |
| 46 | +/* #define long int rather than p9_long so that "unsigned long" is valid */ | |
| 47 | +#define long int | |
| 48 | +#define ulong p9_ulong | |
| 49 | +#define vlong p9_vlong | |
| 50 | +#define uvlong p9_uvlong | |
| 51 | + | |
| 52 | +#define nelem(x) (sizeof(x)/sizeof((x)[0])) | |
| 53 | +#define USED(x) if(x);else | |
| 54 | +#define SET(x) | |
| 55 | + | |
| 56 | +enum | |
| 57 | +{ | |
| 58 | + UTFmax = 3, /* maximum bytes per rune */ | |
| 59 | + Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ | |
| 60 | + Runeself = 0x80, /* rune and UTF sequences are the same (<) */ | |
| 61 | + Runeerror = 0x80 /* decoding error in UTF */ | |
| 62 | +}; | |
| 63 | + | |
| 64 | +/* | |
| 65 | + * new rune routines | |
| 66 | + */ | |
| 67 | +extern int runetochar(char*, Rune*); | |
| 68 | +extern int chartorune(Rune*, char*); | |
| 69 | +extern int runelen(long); | |
| 70 | +extern int fullrune(char*, int); | |
| 71 | + | |
| 72 | +extern int wstrtoutf(char*, Rune*, int); | |
| 73 | +extern int wstrutflen(Rune*); | |
| 74 | + | |
| 75 | +/* | |
| 76 | + * rune routines from converted str routines | |
| 77 | + */ | |
| 78 | +extern long utflen(char*); | |
| 79 | +extern char* utfrune(char*, long); | |
| 80 | +extern char* utfrrune(char*, long); | |
| 81 | + | |
| 82 | +/* | |
| 83 | + * Syscall data structures | |
| 84 | + */ | |
| 85 | +#define MORDER 0x0003 /* mask for bits defining order of mounting */ | |
| 86 | +#define MREPL 0x0000 /* mount replaces object */ | |
| 87 | +#define MBEFORE 0x0001 /* mount goes before others in union directory */ | |
| 88 | +#define MAFTER 0x0002 /* mount goes after others in union directory */ | |
| 89 | +#define MCREATE 0x0004 /* permit creation in mounted directory */ | |
| 90 | +#define MCACHE 0x0010 /* cache some data */ | |
| 91 | +#define MMASK 0x0017 /* all bits on */ | |
| 92 | + | |
| 93 | +#define OREAD 0 /* open for read */ | |
| 94 | +#define OWRITE 1 /* write */ | |
| 95 | +#define ORDWR 2 /* read and write */ | |
| 96 | +#define OEXEC 3 /* execute, == read but check execute permission */ | |
| 97 | +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ | |
| 98 | +#define OCEXEC 32 /* or'ed in, close on exec */ | |
| 99 | +#define ORCLOSE 64 /* or'ed in, remove on close */ | |
| 100 | +#define OEXCL 0x1000 /* or'ed in, exclusive create */ | |
| 101 | + | |
| 102 | +#define NCONT 0 /* continue after note */ | |
| 103 | +#define NDFLT 1 /* terminate after note */ | |
| 104 | +#define NSAVE 2 /* clear note but hold state */ | |
| 105 | +#define NRSTR 3 /* restore saved state */ | |
| 106 | + | |
| 107 | +#define ERRMAX 128 /* max length of error string */ | |
| 108 | +#define KNAMELEN 28 /* max length of name held in kernel */ | |
| 109 | + | |
| 110 | +/* bits in Qid.type */ | |
| 111 | +#define QTDIR 0x80 /* type bit for directories */ | |
| 112 | +#define QTAPPEND 0x40 /* type bit for append only files */ | |
| 113 | +#define QTEXCL 0x20 /* type bit for exclusive use files */ | |
| 114 | +#define QTMOUNT 0x10 /* type bit for mounted channel */ | |
| 115 | +#define QTAUTH 0x08 /* type bit for authentication file */ | |
| 116 | +#define QTFILE 0x00 /* plain file */ | |
| 117 | + | |
| 118 | +/* bits in Dir.mode */ | |
| 119 | +#define DMDIR 0x80000000 /* mode bit for directories */ | |
| 120 | +#define DMAPPEND 0x40000000 /* mode bit for append only files */ | |
| 121 | +#define DMEXCL 0x20000000 /* mode bit for exclusive use files */ | |
| 122 | +#define DMMOUNT 0x10000000 /* mode bit for mounted channel */ | |
| 123 | +#define DMAUTH 0x08000000 /* mode bit for authentication files */ | |
| 124 | +#define DMREAD 0x4 /* mode bit for read permission */ | |
| 125 | +#define DMWRITE 0x2 /* mode bit for write permission */ | |
| 126 | +#define DMEXEC 0x1 /* mode bit for execute permission */ | |
| 127 | + | |
| 128 | +typedef struct Lock | |
| 129 | +{ | |
| 130 | + long key; | |
| 131 | +} Lock; | |
| 132 | + | |
| 133 | +typedef struct QLock | |
| 134 | +{ | |
| 135 | + Lock lk; | |
| 136 | + struct Proc *hold; | |
| 137 | + struct Proc *first; | |
| 138 | + struct Proc *last; | |
| 139 | +} QLock; | |
| 140 | + | |
| 141 | +typedef | |
| 142 | +struct Qid | |
| 143 | +{ | |
| 144 | + uvlong path; | |
| 145 | + ulong vers; | |
| 146 | + uchar type; | |
| 147 | +} Qid; | |
| 148 | + | |
| 149 | +typedef | |
| 150 | +struct Dir { | |
| 151 | + /* system-modified data */ | |
| 152 | + ushort type; /* server type */ | |
| 153 | + uint dev; /* server subtype */ | |
| 154 | + /* file data */ | |
| 155 | + Qid qid; /* unique id from server */ | |
| 156 | + ulong mode; /* permissions */ | |
| 157 | + ulong atime; /* last read time */ | |
| 158 | + ulong mtime; /* last write time */ | |
| 159 | + vlong length; /* file length */ | |
| 160 | + char *name; /* last element of path */ | |
| 161 | + char *uid; /* owner name */ | |
| 162 | + char *gid; /* group name */ | |
| 163 | + char *muid; /* last modifier name */ | |
| 164 | +} Dir; | |
| 165 | + | |
| 166 | +typedef | |
| 167 | +struct Waitmsg | |
| 168 | +{ | |
| 169 | + int pid; /* of loved one */ | |
| 170 | + ulong time[3]; /* of loved one & descendants */ | |
| 171 | + char *msg; | |
| 172 | +} Waitmsg; | |
| 173 | + | |
| 174 | +/* | |
| 175 | + * print routines | |
| 176 | + */ | |
| 177 | +typedef struct Fmt Fmt; | |
| 178 | +struct Fmt{ | |
| 179 | + uchar runes; /* output buffer is runes or chars? */ | |
| 180 | + void *start; /* of buffer */ | |
| 181 | + void *to; /* current place in the buffer */ | |
| 182 | + void *stop; /* end of the buffer; overwritten if flush fails */ | |
| 183 | + int (*flush)(Fmt *); /* called when to == stop */ | |
| 184 | + void *farg; /* to make flush a closure */ | |
| 185 | + int nfmt; /* num chars formatted so far */ | |
| 186 | + va_list args; /* args passed to dofmt */ | |
| 187 | + int r; /* % format Rune */ | |
| 188 | + int width; | |
| 189 | + int prec; | |
| 190 | + ulong flags; | |
| 191 | +}; | |
| 192 | + | |
| 193 | +enum{ | |
| 194 | + FmtWidth = 1, | |
| 195 | + FmtLeft = FmtWidth << 1, | |
| 196 | + FmtPrec = FmtLeft << 1, | |
| 197 | + FmtSharp = FmtPrec << 1, | |
| 198 | + FmtSpace = FmtSharp << 1, | |
| 199 | + FmtSign = FmtSpace << 1, | |
| 200 | + FmtZero = FmtSign << 1, | |
| 201 | + FmtUnsigned = FmtZero << 1, | |
| 202 | + FmtShort = FmtUnsigned << 1, | |
| 203 | + FmtLong = FmtShort << 1, | |
| 204 | + FmtVLong = FmtLong << 1, | |
| 205 | + FmtComma = FmtVLong << 1, | |
| 206 | + FmtByte = FmtComma << 1, | |
| 207 | + | |
| 208 | + FmtFlag = FmtByte << 1 | |
| 209 | +}; | |
| 210 | + | |
| 211 | +extern int print(char*, ...); | |
| 212 | +extern char* seprint(char*, char*, char*, ...); | |
| 213 | +extern char* vseprint(char*, char*, char*, va_list); | |
| 214 | +extern int snprint(char*, int, char*, ...); | |
| 215 | +extern int vsnprint(char*, int, char*, va_list); | |
| 216 | +extern char* smprint(char*, ...); | |
| 217 | +extern char* vsmprint(char*, va_list); | |
| 218 | +extern int sprint(char*, char*, ...); | |
| 219 | +extern int fprint(int, char*, ...); | |
| 220 | +extern int vfprint(int, char*, va_list); | |
| 221 | + | |
| 222 | +extern int (*doquote)(int); | |
| 223 | +extern int runesprint(Rune*, char*, ...); | |
| 224 | +extern int runesnprint(Rune*, int, char*, ...); | |
| 225 | +extern int runevsnprint(Rune*, int, char*, va_list); | |
| 226 | +extern Rune* runeseprint(Rune*, Rune*, char*, ...); | |
| 227 | +extern Rune* runevseprint(Rune*, Rune*, char*, va_list); | |
| 228 | +extern Rune* runesmprint(char*, ...); | |
| 229 | +extern Rune* runevsmprint(char*, va_list); | |
| 230 | + | |
| 231 | +extern int fmtfdinit(Fmt*, int, char*, int); | |
| 232 | +extern int fmtfdflush(Fmt*); | |
| 233 | +extern int fmtstrinit(Fmt*); | |
| 234 | +extern int fmtinstall(int, int (*)(Fmt*)); | |
| 235 | +extern char* fmtstrflush(Fmt*); | |
| 236 | +extern int runefmtstrinit(Fmt*); | |
| 237 | +extern Rune* runefmtstrflush(Fmt*); | |
| 238 | + | |
| 239 | +extern void* mallocz(ulong, int); | |
| 240 | + | |
| 241 | +extern void srand(long); | |
| 242 | +extern int rand(void); | |
| 243 | +extern int nrand(int); | |
| 244 | +extern long lrand(void); | |
| 245 | +extern long lnrand(long); | |
| 246 | +extern double frand(void); | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +#include "lib.h" | |
| 2 | +#include "user.h" | |
| 3 | + | |
| @@ -0,0 +1,340 @@ | ||
| 1 | + | |
| 2 | +#ifndef _MPINT | |
| 3 | +typedef struct mpint mpint; | |
| 4 | +#endif | |
| 5 | + | |
| 6 | +///////////////////////////////////////////////////////// | |
| 7 | +// AES definitions | |
| 8 | +///////////////////////////////////////////////////////// | |
| 9 | + | |
| 10 | +enum | |
| 11 | +{ | |
| 12 | + AESbsize= 16, | |
| 13 | + AESmaxkey= 32, | |
| 14 | + AESmaxrounds= 14 | |
| 15 | +}; | |
| 16 | + | |
| 17 | +typedef struct AESstate AESstate; | |
| 18 | +struct AESstate | |
| 19 | +{ | |
| 20 | + ulong setup; | |
| 21 | + int rounds; | |
| 22 | + int keybytes; | |
| 23 | + uchar key[AESmaxkey]; /* unexpanded key */ | |
| 24 | + u32int ekey[4*(AESmaxrounds + 1)]; /* encryption key */ | |
| 25 | + u32int dkey[4*(AESmaxrounds + 1)]; /* decryption key */ | |
| 26 | + uchar ivec[AESbsize]; /* initialization vector */ | |
| 27 | +}; | |
| 28 | + | |
| 29 | +void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec); | |
| 30 | +void aesCBCencrypt(uchar *p, int len, AESstate *s); | |
| 31 | +void aesCBCdecrypt(uchar *p, int len, AESstate *s); | |
| 32 | + | |
| 33 | +///////////////////////////////////////////////////////// | |
| 34 | +// Blowfish Definitions | |
| 35 | +///////////////////////////////////////////////////////// | |
| 36 | + | |
| 37 | +enum | |
| 38 | +{ | |
| 39 | + BFbsize = 8, | |
| 40 | + BFrounds = 16 | |
| 41 | +}; | |
| 42 | + | |
| 43 | +// 16-round Blowfish | |
| 44 | +typedef struct BFstate BFstate; | |
| 45 | +struct BFstate | |
| 46 | +{ | |
| 47 | + ulong setup; | |
| 48 | + | |
| 49 | + uchar key[56]; | |
| 50 | + uchar ivec[8]; | |
| 51 | + | |
| 52 | + u32int pbox[BFrounds+2]; | |
| 53 | + u32int sbox[1024]; | |
| 54 | +}; | |
| 55 | + | |
| 56 | +void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec); | |
| 57 | +void bfCBCencrypt(uchar*, int, BFstate*); | |
| 58 | +void bfCBCdecrypt(uchar*, int, BFstate*); | |
| 59 | +void bfECBencrypt(uchar*, int, BFstate*); | |
| 60 | +void bfECBdecrypt(uchar*, int, BFstate*); | |
| 61 | + | |
| 62 | +///////////////////////////////////////////////////////// | |
| 63 | +// DES definitions | |
| 64 | +///////////////////////////////////////////////////////// | |
| 65 | + | |
| 66 | +enum | |
| 67 | +{ | |
| 68 | + DESbsize= 8 | |
| 69 | +}; | |
| 70 | + | |
| 71 | +// single des | |
| 72 | +typedef struct DESstate DESstate; | |
| 73 | +struct DESstate | |
| 74 | +{ | |
| 75 | + ulong setup; | |
| 76 | + uchar key[8]; /* unexpanded key */ | |
| 77 | + ulong expanded[32]; /* expanded key */ | |
| 78 | + uchar ivec[8]; /* initialization vector */ | |
| 79 | +}; | |
| 80 | + | |
| 81 | +void setupDESstate(DESstate *s, uchar key[8], uchar *ivec); | |
| 82 | +void des_key_setup(uchar[8], ulong[32]); | |
| 83 | +void block_cipher(ulong*, uchar*, int); | |
| 84 | +void desCBCencrypt(uchar*, int, DESstate*); | |
| 85 | +void desCBCdecrypt(uchar*, int, DESstate*); | |
| 86 | +void desECBencrypt(uchar*, int, DESstate*); | |
| 87 | +void desECBdecrypt(uchar*, int, DESstate*); | |
| 88 | + | |
| 89 | +// for backward compatibility with 7 byte DES key format | |
| 90 | +void des56to64(uchar *k56, uchar *k64); | |
| 91 | +void des64to56(uchar *k64, uchar *k56); | |
| 92 | +void key_setup(uchar[7], ulong[32]); | |
| 93 | + | |
| 94 | +// triple des encrypt/decrypt orderings | |
| 95 | +enum { | |
| 96 | + DES3E= 0, | |
| 97 | + DES3D= 1, | |
| 98 | + DES3EEE= 0, | |
| 99 | + DES3EDE= 2, | |
| 100 | + DES3DED= 5, | |
| 101 | + DES3DDD= 7 | |
| 102 | +}; | |
| 103 | + | |
| 104 | +typedef struct DES3state DES3state; | |
| 105 | +struct DES3state | |
| 106 | +{ | |
| 107 | + ulong setup; | |
| 108 | + uchar key[3][8]; /* unexpanded key */ | |
| 109 | + ulong expanded[3][32]; /* expanded key */ | |
| 110 | + uchar ivec[8]; /* initialization vector */ | |
| 111 | +}; | |
| 112 | + | |
| 113 | +void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec); | |
| 114 | +void triple_block_cipher(ulong keys[3][32], uchar*, int); | |
| 115 | +void des3CBCencrypt(uchar*, int, DES3state*); | |
| 116 | +void des3CBCdecrypt(uchar*, int, DES3state*); | |
| 117 | +void des3ECBencrypt(uchar*, int, DES3state*); | |
| 118 | +void des3ECBdecrypt(uchar*, int, DES3state*); | |
| 119 | + | |
| 120 | +///////////////////////////////////////////////////////// | |
| 121 | +// digests | |
| 122 | +///////////////////////////////////////////////////////// | |
| 123 | + | |
| 124 | +enum | |
| 125 | +{ | |
| 126 | + SHA1dlen= 20, /* SHA digest length */ | |
| 127 | + MD4dlen= 16, /* MD4 digest length */ | |
| 128 | + MD5dlen= 16 /* MD5 digest length */ | |
| 129 | +}; | |
| 130 | + | |
| 131 | +typedef struct DigestState DigestState; | |
| 132 | +struct DigestState | |
| 133 | +{ | |
| 134 | + ulong len; | |
| 135 | + u32int state[5]; | |
| 136 | + uchar buf[128]; | |
| 137 | + int blen; | |
| 138 | + char malloced; | |
| 139 | + char seeded; | |
| 140 | +}; | |
| 141 | +typedef struct DigestState SHAstate; /* obsolete name */ | |
| 142 | +typedef struct DigestState SHA1state; | |
| 143 | +typedef struct DigestState MD5state; | |
| 144 | +typedef struct DigestState MD4state; | |
| 145 | + | |
| 146 | +DigestState* md4(uchar*, ulong, uchar*, DigestState*); | |
| 147 | +DigestState* md5(uchar*, ulong, uchar*, DigestState*); | |
| 148 | +DigestState* sha1(uchar*, ulong, uchar*, DigestState*); | |
| 149 | +DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); | |
| 150 | +DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); | |
| 151 | +char* sha1pickle(SHA1state*); | |
| 152 | +SHA1state* sha1unpickle(char*); | |
| 153 | + | |
| 154 | +///////////////////////////////////////////////////////// | |
| 155 | +// random number generation | |
| 156 | +///////////////////////////////////////////////////////// | |
| 157 | +void genrandom(uchar *buf, int nbytes); | |
| 158 | +void prng(uchar *buf, int nbytes); | |
| 159 | +ulong fastrand(void); | |
| 160 | +ulong nfastrand(ulong); | |
| 161 | + | |
| 162 | +///////////////////////////////////////////////////////// | |
| 163 | +// primes | |
| 164 | +///////////////////////////////////////////////////////// | |
| 165 | +void genprime(mpint *p, int n, int accuracy); // generate an n bit probable prime | |
| 166 | +void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); // prime and generator | |
| 167 | +void genstrongprime(mpint *p, int n, int accuracy); // generate an n bit strong prime | |
| 168 | +void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]); | |
| 169 | +int probably_prime(mpint *n, int nrep); // miller-rabin test | |
| 170 | +int smallprimetest(mpint *p); // returns -1 if not prime, 0 otherwise | |
| 171 | + | |
| 172 | +///////////////////////////////////////////////////////// | |
| 173 | +// rc4 | |
| 174 | +///////////////////////////////////////////////////////// | |
| 175 | +typedef struct RC4state RC4state; | |
| 176 | +struct RC4state | |
| 177 | +{ | |
| 178 | + uchar state[256]; | |
| 179 | + uchar x; | |
| 180 | + uchar y; | |
| 181 | +}; | |
| 182 | + | |
| 183 | +void setupRC4state(RC4state*, uchar*, int); | |
| 184 | +void rc4(RC4state*, uchar*, int); | |
| 185 | +void rc4skip(RC4state*, int); | |
| 186 | +void rc4back(RC4state*, int); | |
| 187 | + | |
| 188 | +///////////////////////////////////////////////////////// | |
| 189 | +// rsa | |
| 190 | +///////////////////////////////////////////////////////// | |
| 191 | +typedef struct RSApub RSApub; | |
| 192 | +typedef struct RSApriv RSApriv; | |
| 193 | + | |
| 194 | +// public/encryption key | |
| 195 | +struct RSApub | |
| 196 | +{ | |
| 197 | + mpint *n; // modulus | |
| 198 | + mpint *ek; // exp (encryption key) | |
| 199 | +}; | |
| 200 | + | |
| 201 | +// private/decryption key | |
| 202 | +struct RSApriv | |
| 203 | +{ | |
| 204 | + RSApub pub; | |
| 205 | + | |
| 206 | + mpint *dk; // exp (decryption key) | |
| 207 | + | |
| 208 | + // precomputed values to help with chinese remainder theorem calc | |
| 209 | + mpint *p; | |
| 210 | + mpint *q; | |
| 211 | + mpint *kp; // dk mod p-1 | |
| 212 | + mpint *kq; // dk mod q-1 | |
| 213 | + mpint *c2; // (inv p) mod q | |
| 214 | +}; | |
| 215 | + | |
| 216 | +RSApriv* rsagen(int nlen, int elen, int rounds); | |
| 217 | +RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q); | |
| 218 | +mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out); | |
| 219 | +mpint* rsadecrypt(RSApriv *k, mpint *in, mpint *out); | |
| 220 | +RSApub* rsapuballoc(void); | |
| 221 | +void rsapubfree(RSApub*); | |
| 222 | +RSApriv* rsaprivalloc(void); | |
| 223 | +void rsaprivfree(RSApriv*); | |
| 224 | +RSApub* rsaprivtopub(RSApriv*); | |
| 225 | +RSApub* X509toRSApub(uchar*, int, char*, int); | |
| 226 | +RSApriv* asn1toRSApriv(uchar*, int); | |
| 227 | +void asn1dump(uchar *der, int len); | |
| 228 | +uchar* decodepem(char *s, char *type, int *len); | |
| 229 | +uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen); | |
| 230 | +uchar* X509req(RSApriv *priv, char *subj, int *certlen); | |
| 231 | +char* X509verify(uchar *cert, int ncert, RSApub *pk); | |
| 232 | +void X509dump(uchar *cert, int ncert); | |
| 233 | +///////////////////////////////////////////////////////// | |
| 234 | +// elgamal | |
| 235 | +///////////////////////////////////////////////////////// | |
| 236 | +typedef struct EGpub EGpub; | |
| 237 | +typedef struct EGpriv EGpriv; | |
| 238 | +typedef struct EGsig EGsig; | |
| 239 | + | |
| 240 | +// public/encryption key | |
| 241 | +struct EGpub | |
| 242 | +{ | |
| 243 | + mpint *p; // modulus | |
| 244 | + mpint *alpha; // generator | |
| 245 | + mpint *key; // (encryption key) alpha**secret mod p | |
| 246 | +}; | |
| 247 | + | |
| 248 | +// private/decryption key | |
| 249 | +struct EGpriv | |
| 250 | +{ | |
| 251 | + EGpub pub; | |
| 252 | + mpint *secret; // (decryption key) | |
| 253 | +}; | |
| 254 | + | |
| 255 | +// signature | |
| 256 | +struct EGsig | |
| 257 | +{ | |
| 258 | + mpint *r, *s; | |
| 259 | +}; | |
| 260 | + | |
| 261 | +EGpriv* eggen(int nlen, int rounds); | |
| 262 | +mpint* egencrypt(EGpub *k, mpint *in, mpint *out); | |
| 263 | +mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out); | |
| 264 | +EGsig* egsign(EGpriv *k, mpint *m); | |
| 265 | +int egverify(EGpub *k, EGsig *sig, mpint *m); | |
| 266 | +EGpub* egpuballoc(void); | |
| 267 | +void egpubfree(EGpub*); | |
| 268 | +EGpriv* egprivalloc(void); | |
| 269 | +void egprivfree(EGpriv*); | |
| 270 | +EGsig* egsigalloc(void); | |
| 271 | +void egsigfree(EGsig*); | |
| 272 | +EGpub* egprivtopub(EGpriv*); | |
| 273 | + | |
| 274 | +///////////////////////////////////////////////////////// | |
| 275 | +// dsa | |
| 276 | +///////////////////////////////////////////////////////// | |
| 277 | +typedef struct DSApub DSApub; | |
| 278 | +typedef struct DSApriv DSApriv; | |
| 279 | +typedef struct DSAsig DSAsig; | |
| 280 | + | |
| 281 | +// public/encryption key | |
| 282 | +struct DSApub | |
| 283 | +{ | |
| 284 | + mpint *p; // modulus | |
| 285 | + mpint *q; // group order, q divides p-1 | |
| 286 | + mpint *alpha; // group generator | |
| 287 | + mpint *key; // (encryption key) alpha**secret mod p | |
| 288 | +}; | |
| 289 | + | |
| 290 | +// private/decryption key | |
| 291 | +struct DSApriv | |
| 292 | +{ | |
| 293 | + DSApub pub; | |
| 294 | + mpint *secret; // (decryption key) | |
| 295 | +}; | |
| 296 | + | |
| 297 | +// signature | |
| 298 | +struct DSAsig | |
| 299 | +{ | |
| 300 | + mpint *r, *s; | |
| 301 | +}; | |
| 302 | + | |
| 303 | +DSApriv* dsagen(DSApub *opub); | |
| 304 | +DSAsig* dsasign(DSApriv *k, mpint *m); | |
| 305 | +int dsaverify(DSApub *k, DSAsig *sig, mpint *m); | |
| 306 | +DSApub* dsapuballoc(void); | |
| 307 | +void dsapubfree(DSApub*); | |
| 308 | +DSApriv* dsaprivalloc(void); | |
| 309 | +void dsaprivfree(DSApriv*); | |
| 310 | +DSAsig* dsasigalloc(void); | |
| 311 | +void dsasigfree(DSAsig*); | |
| 312 | +DSApub* dsaprivtopub(DSApriv*); | |
| 313 | + | |
| 314 | +///////////////////////////////////////////////////////// | |
| 315 | +// TLS | |
| 316 | +///////////////////////////////////////////////////////// | |
| 317 | +typedef struct Thumbprint{ | |
| 318 | + struct Thumbprint *next; | |
| 319 | + uchar sha1[SHA1dlen]; | |
| 320 | +} Thumbprint; | |
| 321 | + | |
| 322 | +typedef struct TLSconn{ | |
| 323 | + char dir[40]; // connection directory | |
| 324 | + uchar *cert; // certificate (local on input, remote on output) | |
| 325 | + uchar *sessionID; | |
| 326 | + int certlen, sessionIDlen; | |
| 327 | + int (*trace)(char*fmt, ...); | |
| 328 | +} TLSconn; | |
| 329 | + | |
| 330 | +// tlshand.c | |
| 331 | +extern int tlsClient(int fd, TLSconn *c); | |
| 332 | +extern int tlsServer(int fd, TLSconn *c); | |
| 333 | + | |
| 334 | +// thumb.c | |
| 335 | +extern Thumbprint* initThumbprints(char *ok, char *crl); | |
| 336 | +extern void freeThumbprints(Thumbprint *ok); | |
| 337 | +extern int okThumbprint(uchar *sha1, Thumbprint *ok); | |
| 338 | + | |
| 339 | +// readcert.c | |
| 340 | +extern uchar *readcert(char *filename, int *pcertlen); | |
| @@ -0,0 +1,200 @@ | ||
| 1 | +#pragma src "/sys/src/libmemdraw" | |
| 2 | +#pragma lib "libmemdraw.a" | |
| 3 | + | |
| 4 | +typedef struct Memimage Memimage; | |
| 5 | +typedef struct Memdata Memdata; | |
| 6 | +typedef struct Memsubfont Memsubfont; | |
| 7 | +typedef struct Memlayer Memlayer; | |
| 8 | +typedef struct Memcmap Memcmap; | |
| 9 | +typedef struct Memdrawparam Memdrawparam; | |
| 10 | + | |
| 11 | +/* | |
| 12 | + * Memdata is allocated from main pool, but .data from the image pool. | |
| 13 | + * Memdata is allocated separately to permit patching its pointer after | |
| 14 | + * compaction when windows share the image data. | |
| 15 | + * The first word of data is a back pointer to the Memdata, to find | |
| 16 | + * The word to patch. | |
| 17 | + */ | |
| 18 | + | |
| 19 | +struct Memdata | |
| 20 | +{ | |
| 21 | + ulong *base; /* allocated data pointer */ | |
| 22 | + uchar *bdata; /* pointer to first byte of actual data; word-aligned */ | |
| 23 | + int ref; /* number of Memimages using this data */ | |
| 24 | + void* imref; | |
| 25 | + int allocd; /* is this malloc'd? */ | |
| 26 | +}; | |
| 27 | + | |
| 28 | +enum { | |
| 29 | + Frepl = 1<<0, /* is replicated */ | |
| 30 | + Fsimple = 1<<1, /* is 1x1 */ | |
| 31 | + Fgrey = 1<<2, /* is grey */ | |
| 32 | + Falpha = 1<<3, /* has explicit alpha */ | |
| 33 | + Fcmap = 1<<4, /* has cmap channel */ | |
| 34 | + Fbytes = 1<<5, /* has only 8-bit channels */ | |
| 35 | +}; | |
| 36 | + | |
| 37 | +struct Memimage | |
| 38 | +{ | |
| 39 | + Rectangle r; /* rectangle in data area, local coords */ | |
| 40 | + Rectangle clipr; /* clipping region */ | |
| 41 | + int depth; /* number of bits of storage per pixel */ | |
| 42 | + int nchan; /* number of channels */ | |
| 43 | + ulong chan; /* channel descriptions */ | |
| 44 | + Memcmap *cmap; | |
| 45 | + | |
| 46 | + Memdata *data; /* pointer to data; shared by windows in this image */ | |
| 47 | + int zero; /* data->bdata+zero==&byte containing (0,0) */ | |
| 48 | + ulong width; /* width in words of a single scan line */ | |
| 49 | + Memlayer *layer; /* nil if not a layer*/ | |
| 50 | + ulong flags; | |
| 51 | + | |
| 52 | + int shift[NChan]; | |
| 53 | + int mask[NChan]; | |
| 54 | + int nbits[NChan]; | |
| 55 | + | |
| 56 | + void *X; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +struct Memcmap | |
| 60 | +{ | |
| 61 | + uchar cmap2rgb[3*256]; | |
| 62 | + uchar rgb2cmap[16*16*16]; | |
| 63 | +}; | |
| 64 | + | |
| 65 | +/* | |
| 66 | + * Subfonts | |
| 67 | + * | |
| 68 | + * given char c, Subfont *f, Fontchar *i, and Point p, one says | |
| 69 | + * i = f->info+c; | |
| 70 | + * draw(b, Rect(p.x+i->left, p.y+i->top, | |
| 71 | + * p.x+i->left+((i+1)->x-i->x), p.y+i->bottom), | |
| 72 | + * color, f->bits, Pt(i->x, i->top)); | |
| 73 | + * p.x += i->width; | |
| 74 | + * to draw characters in the specified color (itself a Memimage) in Memimage b. | |
| 75 | + */ | |
| 76 | + | |
| 77 | +struct Memsubfont | |
| 78 | +{ | |
| 79 | + char *name; | |
| 80 | + short n; /* number of chars in font */ | |
| 81 | + uchar height; /* height of bitmap */ | |
| 82 | + char ascent; /* top of bitmap to baseline */ | |
| 83 | + Fontchar *info; /* n+1 character descriptors */ | |
| 84 | + Memimage *bits; /* of font */ | |
| 85 | +}; | |
| 86 | + | |
| 87 | +/* | |
| 88 | + * Encapsulated parameters and information for sub-draw routines. | |
| 89 | + */ | |
| 90 | +enum { | |
| 91 | + Simplesrc=1<<0, | |
| 92 | + Simplemask=1<<1, | |
| 93 | + Replsrc=1<<2, | |
| 94 | + Replmask=1<<3, | |
| 95 | + Fullmask=1<<4, | |
| 96 | +}; | |
| 97 | +struct Memdrawparam | |
| 98 | +{ | |
| 99 | + Memimage *dst; | |
| 100 | + Rectangle r; | |
| 101 | + Memimage *src; | |
| 102 | + Rectangle sr; | |
| 103 | + Memimage *mask; | |
| 104 | + Rectangle mr; | |
| 105 | + int op; | |
| 106 | + | |
| 107 | + ulong state; | |
| 108 | + ulong mval; /* if Simplemask, the mask pixel in mask format */ | |
| 109 | + ulong mrgba; /* mval in rgba */ | |
| 110 | + ulong sval; /* if Simplesrc, the source pixel in src format */ | |
| 111 | + ulong srgba; /* sval in rgba */ | |
| 112 | + ulong sdval; /* sval in dst format */ | |
| 113 | +}; | |
| 114 | + | |
| 115 | +/* | |
| 116 | + * Memimage management | |
| 117 | + */ | |
| 118 | + | |
| 119 | +extern Memimage* allocmemimage(Rectangle, ulong); | |
| 120 | +extern Memimage* _allocmemimage(Rectangle, ulong); | |
| 121 | +extern Memimage* allocmemimaged(Rectangle, ulong, Memdata*, void*); | |
| 122 | +extern Memimage* readmemimage(int); | |
| 123 | +extern Memimage* creadmemimage(int); | |
| 124 | +extern int writememimage(int, Memimage*); | |
| 125 | +extern void freememimage(Memimage*); | |
| 126 | +extern int _loadmemimage(Memimage*, Rectangle, uchar*, int); | |
| 127 | +extern int _cloadmemimage(Memimage*, Rectangle, uchar*, int); | |
| 128 | +extern int _unloadmemimage(Memimage*, Rectangle, uchar*, int); | |
| 129 | +extern int loadmemimage(Memimage*, Rectangle, uchar*, int); | |
| 130 | +extern int cloadmemimage(Memimage*, Rectangle, uchar*, int); | |
| 131 | +extern int unloadmemimage(Memimage*, Rectangle, uchar*, int); | |
| 132 | +extern ulong* wordaddr(Memimage*, Point); | |
| 133 | +extern uchar* byteaddr(Memimage*, Point); | |
| 134 | +extern int drawclip(Memimage*, Rectangle*, Memimage*, Point*, Memimage*, Point*, Rectangle*, Rectangle*); | |
| 135 | +extern void memfillcolor(Memimage*, ulong); | |
| 136 | +extern int memsetchan(Memimage*, ulong); | |
| 137 | + | |
| 138 | +/* | |
| 139 | + * Graphics | |
| 140 | + */ | |
| 141 | +extern void memdraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int); | |
| 142 | +extern void memline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int); | |
| 143 | +extern void mempoly(Memimage*, Point*, int, int, int, int, Memimage*, Point, int); | |
| 144 | +extern void memfillpoly(Memimage*, Point*, int, int, Memimage*, Point, int); | |
| 145 | +extern void _memfillpolysc(Memimage*, Point*, int, int, Memimage*, Point, int, int, int, int); | |
| 146 | +extern Memdrawparam* _memimagedrawsetup(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int); | |
| 147 | +extern void _memimagedraw(Memdrawparam*); | |
| 148 | +extern void memimagedraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int); | |
| 149 | +extern int hwdraw(Memdrawparam*); | |
| 150 | +extern void memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int); | |
| 151 | +extern void _memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, Rectangle, int); | |
| 152 | +extern Point memimagestring(Memimage*, Point, Memimage*, Point, Memsubfont*, char*); | |
| 153 | +extern void memellipse(Memimage*, Point, int, int, int, Memimage*, Point, int); | |
| 154 | +extern void memarc(Memimage*, Point, int, int, int, Memimage*, Point, int, int, int); | |
| 155 | +extern Rectangle memlinebbox(Point, Point, int, int, int); | |
| 156 | +extern int memlineendsize(int); | |
| 157 | +extern void _memmkcmap(void); | |
| 158 | +extern void memimageinit(void); | |
| 159 | + | |
| 160 | +/* | |
| 161 | + * Subfont management | |
| 162 | + */ | |
| 163 | +extern Memsubfont* allocmemsubfont(char*, int, int, int, Fontchar*, Memimage*); | |
| 164 | +extern Memsubfont* openmemsubfont(char*); | |
| 165 | +extern void freememsubfont(Memsubfont*); | |
| 166 | +extern Point memsubfontwidth(Memsubfont*, char*); | |
| 167 | +extern Memsubfont* getmemdefont(void); | |
| 168 | + | |
| 169 | +/* | |
| 170 | + * Predefined | |
| 171 | + */ | |
| 172 | +extern Memimage* memwhite; | |
| 173 | +extern Memimage* memblack; | |
| 174 | +extern Memimage* memopaque; | |
| 175 | +extern Memimage* memtransparent; | |
| 176 | +extern Memcmap *memdefcmap; | |
| 177 | + | |
| 178 | +/* | |
| 179 | + * Kernel interface | |
| 180 | + */ | |
| 181 | +void memimagemove(void*, void*); | |
| 182 | + | |
| 183 | +/* | |
| 184 | + * Kernel cruft | |
| 185 | + */ | |
| 186 | +extern void rdb(void); | |
| 187 | +extern int iprint(char*, ...); | |
| 188 | +#pragma varargck argpos iprint 1 | |
| 189 | +extern int drawdebug; | |
| 190 | + | |
| 191 | +/* | |
| 192 | + * doprint interface: numbconv bit strings | |
| 193 | + */ | |
| 194 | +#pragma varargck type "llb" vlong | |
| 195 | +#pragma varargck type "llb" uvlong | |
| 196 | +#pragma varargck type "lb" long | |
| 197 | +#pragma varargck type "lb" ulong | |
| 198 | +#pragma varargck type "b" int | |
| 199 | +#pragma varargck type "b" uint | |
| 200 | + | |
| @@ -0,0 +1,51 @@ | ||
| 1 | +#pragma src "/sys/src/libmemlayer" | |
| 2 | +#pragma lib "libmemlayer.a" | |
| 3 | + | |
| 4 | +typedef struct Memscreen Memscreen; | |
| 5 | +typedef void (*Refreshfn)(Memimage*, Rectangle, void*); | |
| 6 | + | |
| 7 | +struct Memscreen | |
| 8 | +{ | |
| 9 | + Memimage *frontmost; /* frontmost layer on screen */ | |
| 10 | + Memimage *rearmost; /* rearmost layer on screen */ | |
| 11 | + Memimage *image; /* upon which all layers are drawn */ | |
| 12 | + Memimage *fill; /* if non-zero, picture to use when repainting */ | |
| 13 | +}; | |
| 14 | + | |
| 15 | +struct Memlayer | |
| 16 | +{ | |
| 17 | + Rectangle screenr; /* true position of layer on screen */ | |
| 18 | + Point delta; /* add delta to go from image coords to screen */ | |
| 19 | + Memscreen *screen; /* screen this layer belongs to */ | |
| 20 | + Memimage *front; /* window in front of this one */ | |
| 21 | + Memimage *rear; /* window behind this one*/ | |
| 22 | + int clear; /* layer is fully visible */ | |
| 23 | + Memimage *save; /* save area for obscured parts */ | |
| 24 | + Refreshfn refreshfn; /* function to call to refresh obscured parts if save==nil */ | |
| 25 | + void *refreshptr; /* argument to refreshfn */ | |
| 26 | +}; | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * These functions accept local coordinates | |
| 30 | + */ | |
| 31 | +int memload(Memimage*, Rectangle, uchar*, int, int); | |
| 32 | +int memunload(Memimage*, Rectangle, uchar*, int); | |
| 33 | + | |
| 34 | +/* | |
| 35 | + * All these functions accept screen coordinates, not local ones. | |
| 36 | + */ | |
| 37 | +void _memlayerop(void (*fn)(Memimage*, Rectangle, Rectangle, void*, int), Memimage*, Rectangle, Rectangle, void*); | |
| 38 | +Memimage* memlalloc(Memscreen*, Rectangle, Refreshfn, void*, ulong); | |
| 39 | +void memldelete(Memimage*); | |
| 40 | +void memlfree(Memimage*); | |
| 41 | +void memltofront(Memimage*); | |
| 42 | +void memltofrontn(Memimage**, int); | |
| 43 | +void _memltofrontfill(Memimage*, int); | |
| 44 | +void memltorear(Memimage*); | |
| 45 | +void memltorearn(Memimage**, int); | |
| 46 | +int memlsetrefresh(Memimage*, Refreshfn, void*); | |
| 47 | +void memlhide(Memimage*, Rectangle); | |
| 48 | +void memlexpose(Memimage*, Rectangle); | |
| 49 | +void _memlsetclear(Memscreen*); | |
| 50 | +int memlorigin(Memimage*, Point, Point); | |
| 51 | +void memlnorefresh(Memimage*, Rectangle, void*); | |
| @@ -0,0 +1,134 @@ | ||
| 1 | +#define _MPINT 1 | |
| 2 | + | |
| 3 | +// the code assumes mpdigit to be at least an int | |
| 4 | +// mpdigit must be an atomic type. mpdigit is defined | |
| 5 | +// in the architecture specific u.h | |
| 6 | + | |
| 7 | +typedef struct mpint mpint; | |
| 8 | + | |
| 9 | +struct mpint | |
| 10 | +{ | |
| 11 | + int sign; // +1 or -1 | |
| 12 | + int size; // allocated digits | |
| 13 | + int top; // significant digits | |
| 14 | + mpdigit *p; | |
| 15 | + char flags; | |
| 16 | +}; | |
| 17 | + | |
| 18 | +enum | |
| 19 | +{ | |
| 20 | + MPstatic= 0x01, | |
| 21 | + Dbytes= sizeof(mpdigit), // bytes per digit | |
| 22 | + Dbits= Dbytes*8 // bits per digit | |
| 23 | +}; | |
| 24 | + | |
| 25 | +// allocation | |
| 26 | +void mpsetminbits(int n); // newly created mpint's get at least n bits | |
| 27 | +mpint* mpnew(int n); // create a new mpint with at least n bits | |
| 28 | +void mpfree(mpint *b); | |
| 29 | +void mpbits(mpint *b, int n); // ensure that b has at least n bits | |
| 30 | +void mpnorm(mpint *b); // dump leading zeros | |
| 31 | +mpint* mpcopy(mpint *b); | |
| 32 | +void mpassign(mpint *old, mpint *new); | |
| 33 | + | |
| 34 | +// random bits | |
| 35 | +mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b); | |
| 36 | + | |
| 37 | +// conversion | |
| 38 | +mpint* strtomp(char*, char**, int, mpint*); // ascii | |
| 39 | +int mpfmt(Fmt*); | |
| 40 | +char* mptoa(mpint*, int, char*, int); | |
| 41 | +mpint* letomp(uchar*, uint, mpint*); // byte array, little-endian | |
| 42 | +int mptole(mpint*, uchar*, uint, uchar**); | |
| 43 | +mpint* betomp(uchar*, uint, mpint*); // byte array, little-endian | |
| 44 | +int mptobe(mpint*, uchar*, uint, uchar**); | |
| 45 | +uint mptoui(mpint*); // unsigned int | |
| 46 | +mpint* uitomp(uint, mpint*); | |
| 47 | +int mptoi(mpint*); // int | |
| 48 | +mpint* itomp(int, mpint*); | |
| 49 | +uvlong mptouv(mpint*); // unsigned vlong | |
| 50 | +mpint* uvtomp(uvlong, mpint*); | |
| 51 | +vlong mptov(mpint*); // vlong | |
| 52 | +mpint* vtomp(vlong, mpint*); | |
| 53 | + | |
| 54 | +// divide 2 digits by one | |
| 55 | +void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); | |
| 56 | + | |
| 57 | +// in the following, the result mpint may be | |
| 58 | +// the same as one of the inputs. | |
| 59 | +void mpadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 | |
| 60 | +void mpsub(mpint *b1, mpint *b2, mpint *diff); // diff = b1-b2 | |
| 61 | +void mpleft(mpint *b, int shift, mpint *res); // res = b<<shift | |
| 62 | +void mpright(mpint *b, int shift, mpint *res); // res = b>>shift | |
| 63 | +void mpmul(mpint *b1, mpint *b2, mpint *prod); // prod = b1*b2 | |
| 64 | +void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); // res = b**e mod m | |
| 65 | +void mpmod(mpint *b, mpint *m, mpint *remainder); // remainder = b mod m | |
| 66 | + | |
| 67 | +// quotient = dividend/divisor, remainder = dividend % divisor | |
| 68 | +void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder); | |
| 69 | + | |
| 70 | +// return neg, 0, pos as b1-b2 is neg, 0, pos | |
| 71 | +int mpcmp(mpint *b1, mpint *b2); | |
| 72 | + | |
| 73 | +// extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d | |
| 74 | +void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y); | |
| 75 | + | |
| 76 | +// res = b**-1 mod m | |
| 77 | +void mpinvert(mpint *b, mpint *m, mpint *res); | |
| 78 | + | |
| 79 | +// bit counting | |
| 80 | +int mpsignif(mpint*); // number of sigificant bits in mantissa | |
| 81 | +int mplowbits0(mpint*); // k, where n = 2**k * q for odd q | |
| 82 | + | |
| 83 | +// well known constants | |
| 84 | +extern mpint *mpzero, *mpone, *mptwo; | |
| 85 | + | |
| 86 | +// sum[0:alen] = a[0:alen-1] + b[0:blen-1] | |
| 87 | +// prereq: alen >= blen, sum has room for alen+1 digits | |
| 88 | +void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum); | |
| 89 | + | |
| 90 | +// diff[0:alen-1] = a[0:alen-1] - b[0:blen-1] | |
| 91 | +// prereq: alen >= blen, diff has room for alen digits | |
| 92 | +void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff); | |
| 93 | + | |
| 94 | +// p[0:n] += m * b[0:n-1] | |
| 95 | +// prereq: p has room for n+1 digits | |
| 96 | +void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p); | |
| 97 | + | |
| 98 | +// p[0:n] -= m * b[0:n-1] | |
| 99 | +// prereq: p has room for n+1 digits | |
| 100 | +int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p); | |
| 101 | + | |
| 102 | +// p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1] | |
| 103 | +// prereq: alen >= blen, p has room for m*n digits | |
| 104 | +void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p); | |
| 105 | + | |
| 106 | +// sign of a - b or zero if the same | |
| 107 | +int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen); | |
| 108 | + | |
| 109 | +// divide the 2 digit dividend by the one digit divisor and stick in quotient | |
| 110 | +// we assume that the result is one digit - overflow is all 1's | |
| 111 | +void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); | |
| 112 | + | |
| 113 | +// playing with magnitudes | |
| 114 | +int mpmagcmp(mpint *b1, mpint *b2); | |
| 115 | +void mpmagadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 | |
| 116 | +void mpmagsub(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2 | |
| 117 | + | |
| 118 | +// chinese remainder theorem | |
| 119 | +typedef struct CRTpre CRTpre; // precomputed values for converting | |
| 120 | + // twixt residues and mpint | |
| 121 | +typedef struct CRTres CRTres; // residue form of an mpint | |
| 122 | + | |
| 123 | +struct CRTres | |
| 124 | +{ | |
| 125 | + int n; // number of residues | |
| 126 | + mpint *r[1]; // residues | |
| 127 | +}; | |
| 128 | + | |
| 129 | +CRTpre* crtpre(int, mpint**); // precompute conversion values | |
| 130 | +CRTres* crtin(CRTpre*, mpint*); // convert mpint to residues | |
| 131 | +void crtout(CRTpre*, CRTres*, mpint*); // convert residues to mpint | |
| 132 | +void crtprefree(CRTpre*); | |
| 133 | +void crtresfree(CRTres*); | |
| 134 | + | |
| @@ -0,0 +1,26 @@ | ||
| 1 | +#include "dtos.h" | |
| 2 | + | |
| 3 | +/* avoid name conflicts */ | |
| 4 | +#undef accept | |
| 5 | +#undef listen | |
| 6 | + | |
| 7 | +/* sys calls */ | |
| 8 | +#undef bind | |
| 9 | +#undef chdir | |
| 10 | +#undef close | |
| 11 | +#undef create | |
| 12 | +#undef dup | |
| 13 | +#undef export | |
| 14 | +#undef fstat | |
| 15 | +#undef fwstat | |
| 16 | +#undef mount | |
| 17 | +#undef open | |
| 18 | +#undef start | |
| 19 | +#undef read | |
| 20 | +#undef remove | |
| 21 | +#undef seek | |
| 22 | +#undef stat | |
| 23 | +#undef write | |
| 24 | +#undef wstat | |
| 25 | +#undef unmount | |
| 26 | +#undef pipe | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +#include <stdio.h> | |
| 2 | +#include <stdlib.h> | |
| 3 | +#include <string.h> | |
| 4 | +#include <math.h> | |
| 5 | +#include <fcntl.h> | |
| 6 | +#include <setjmp.h> | |
| 7 | +#include <time.h> | |
| 8 | +#include <assert.h> | |
| 9 | +#include <unistd.h> | |
| 10 | +#include <stdarg.h> | |
| 11 | + | |
| 12 | + | |
| 13 | +typedef long long p9_vlong; | |
| 14 | +typedef unsigned long long p9_uvlong; | |
| @@ -0,0 +1,65 @@ | ||
| 1 | +/* sys calls */ | |
| 2 | +#define bind sysbind | |
| 3 | +#define chdir syschdir | |
| 4 | +#define close sysclose | |
| 5 | +#define create syscreate | |
| 6 | +#define dup sysdup | |
| 7 | +#define export sysexport | |
| 8 | +#define fstat sysfstat | |
| 9 | +#define fwstat sysfwstat | |
| 10 | +#define mount sysmount | |
| 11 | +#define open sysopen | |
| 12 | +#define read sysread | |
| 13 | +#define remove sysremove | |
| 14 | +#define seek sysseek | |
| 15 | +#define stat sysstat | |
| 16 | +#define write syswrite | |
| 17 | +#define wstat syswstat | |
| 18 | +#define unmount sysunmount | |
| 19 | +#define pipe syspipe | |
| 20 | +#define rendezvous sysrendezvous | |
| 21 | +#define getpid sysgetpid | |
| 22 | +#define time systime | |
| 23 | +#define nsec sysnsec | |
| 24 | +#define pread syspread | |
| 25 | +#define pwrite syspwrite | |
| 26 | + | |
| 27 | +extern int bind(char*, char*, int); | |
| 28 | +extern int chdir(char*); | |
| 29 | +extern int close(int); | |
| 30 | +extern int create(char*, int, ulong); | |
| 31 | +extern int dup(int, int); | |
| 32 | +extern int export(int); | |
| 33 | +extern int fstat(int, uchar*, int); | |
| 34 | +extern int fwstat(int, uchar*, int); | |
| 35 | +extern int mount(int, int, char*, int, char*); | |
| 36 | +extern int unmount(char*, char*); | |
| 37 | +extern int open(char*, int); | |
| 38 | +extern int pipe(int*); | |
| 39 | +extern long read(int, void*, long); | |
| 40 | +extern long readn(int, void*, long); | |
| 41 | +extern int remove(char*); | |
| 42 | +extern vlong seek(int, vlong, int); | |
| 43 | +extern int stat(char*, uchar*, int); | |
| 44 | +extern long write(int, void*, long); | |
| 45 | +extern int wstat(char*, uchar*, int); | |
| 46 | + | |
| 47 | +extern Dir *dirstat(char*); | |
| 48 | +extern Dir *dirfstat(int); | |
| 49 | +extern int dirwstat(char*, Dir*); | |
| 50 | +extern int dirfwstat(int, Dir*); | |
| 51 | +extern long dirread(int, Dir*, long); | |
| 52 | + | |
| 53 | +/* | |
| 54 | + * network dialing and authentication | |
| 55 | + */ | |
| 56 | +#define NETPATHLEN 40 | |
| 57 | +extern int accept(int, char*); | |
| 58 | +extern int announce(char*, char*); | |
| 59 | +extern int dial(char*, char*, char*, int*); | |
| 60 | +extern int hangup(int); | |
| 61 | +extern int listen(char*, char*); | |
| 62 | +extern char *netmkaddr(char*, char*, char*); | |
| 63 | +extern int reject(int, char*, char*); | |
| 64 | + | |
| 65 | +extern char* argv0; | |
Empty file added.
| @@ -0,0 +1,6 @@ | ||
| 1 | +#include <stdio.h> | |
| 2 | + | |
| 3 | +void | |
| 4 | +main(void) | |
| 5 | +{ | |
| 6 | +} | |
| @@ -0,0 +1,50 @@ | ||
| 1 | +LIB=libkern.a | |
| 2 | +CC=gcc | |
| 3 | +CFLAGS=-I../include -I. -c -ggdb -D_THREAD_SAFE -pthread | |
| 4 | +O=o | |
| 5 | +#CC=cl | |
| 6 | +#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -I../include -DWINDOWS | |
| 7 | +#O=obj | |
| 8 | + | |
| 9 | +OFILES=\ | |
| 10 | + allocb.$O\ | |
| 11 | + cache.$O\ | |
| 12 | + chan.$O\ | |
| 13 | + data.$O\ | |
| 14 | + dev.$O\ | |
| 15 | + devcons.$O\ | |
| 16 | + devdraw.$O\ | |
| 17 | + devfs.$O\ | |
| 18 | + devip.$O\ | |
| 19 | + devip-posix.$O\ | |
| 20 | + devmnt.$O\ | |
| 21 | + devmouse.$O\ | |
| 22 | + devpipe.$O\ | |
| 23 | + devroot.$O\ | |
| 24 | + devssl.$O\ | |
| 25 | + devtab.$O\ | |
| 26 | + error.$O\ | |
| 27 | + parse.$O\ | |
| 28 | + pgrp.$O\ | |
| 29 | + posix.$O\ | |
| 30 | + procinit.$O\ | |
| 31 | + rwlock.$O\ | |
| 32 | + sleep.$O\ | |
| 33 | + smalloc.$O\ | |
| 34 | + stub.$O\ | |
| 35 | + sysfile.$O\ | |
| 36 | + sysproc.$O\ | |
| 37 | + qio.$O\ | |
| 38 | + qlock.$O\ | |
| 39 | + term.$O\ | |
| 40 | + todo.$O\ | |
| 41 | + uart.$O\ | |
| 42 | + waserror.$O | |
| 43 | + | |
| 44 | +$(LIB): $(OFILES) | |
| 45 | + ar r $(LIB) $(OFILES) | |
| 46 | + ranlib $(LIB) | |
| 47 | + | |
| 48 | +%.$O: %.c | |
| 49 | + $(CC) $(CFLAGS) $*.c | |
| 50 | + | |
| @@ -0,0 +1,165 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +enum | |
| 8 | +{ | |
| 9 | + Hdrspc = 64, /* leave room for high-level headers */ | |
| 10 | + Bdead = 0x51494F42, /* "QIOB" */ | |
| 11 | +}; | |
| 12 | + | |
| 13 | +struct | |
| 14 | +{ | |
| 15 | + Lock lk; | |
| 16 | + ulong bytes; | |
| 17 | +} ialloc; | |
| 18 | + | |
| 19 | +static Block* | |
| 20 | +_allocb(int size) | |
| 21 | +{ | |
| 22 | + Block *b; | |
| 23 | + ulong addr; | |
| 24 | + | |
| 25 | + if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil) | |
| 26 | + return nil; | |
| 27 | + | |
| 28 | + b->next = nil; | |
| 29 | + b->list = nil; | |
| 30 | + b->free = 0; | |
| 31 | + b->flag = 0; | |
| 32 | + | |
| 33 | + /* align start of data portion by rounding up */ | |
| 34 | + addr = (ulong)b; | |
| 35 | + addr = ROUND(addr + sizeof(Block), BLOCKALIGN); | |
| 36 | + b->base = (uchar*)addr; | |
| 37 | + | |
| 38 | + /* align end of data portion by rounding down */ | |
| 39 | + b->lim = ((uchar*)b) + sizeof(Block)+size+Hdrspc; | |
| 40 | + addr = (ulong)(b->lim); | |
| 41 | + addr = addr & ~(BLOCKALIGN-1); | |
| 42 | + b->lim = (uchar*)addr; | |
| 43 | + | |
| 44 | + /* leave sluff at beginning for added headers */ | |
| 45 | + b->rp = b->lim - ROUND(size, BLOCKALIGN); | |
| 46 | + if(b->rp < b->base) | |
| 47 | + panic("_allocb"); | |
| 48 | + b->wp = b->rp; | |
| 49 | + | |
| 50 | + return b; | |
| 51 | +} | |
| 52 | + | |
| 53 | +Block* | |
| 54 | +allocb(int size) | |
| 55 | +{ | |
| 56 | + Block *b; | |
| 57 | + | |
| 58 | + /* | |
| 59 | + * Check in a process and wait until successful. | |
| 60 | + * Can still error out of here, though. | |
| 61 | + */ | |
| 62 | + if(up == nil) | |
| 63 | + panic("allocb without up: %luX\n", getcallerpc(&size)); | |
| 64 | + if((b = _allocb(size)) == nil){ | |
| 65 | + panic("allocb: no memory for %d bytes\n", size); | |
| 66 | + } | |
| 67 | + setmalloctag(b, getcallerpc(&size)); | |
| 68 | + | |
| 69 | + return b; | |
| 70 | +} | |
| 71 | + | |
| 72 | +Block* | |
| 73 | +iallocb(int size) | |
| 74 | +{ | |
| 75 | + Block *b; | |
| 76 | + static int m1, m2; | |
| 77 | + | |
| 78 | + if(ialloc.bytes > conf.ialloc){ | |
| 79 | + if((m1++%10000)==0) | |
| 80 | + print("iallocb: limited %lud/%lud\n", | |
| 81 | + ialloc.bytes, conf.ialloc); | |
| 82 | + return 0; | |
| 83 | + } | |
| 84 | + | |
| 85 | + if((b = _allocb(size)) == nil){ | |
| 86 | + if((m2++%10000)==0) | |
| 87 | + print("iallocb: no memory %lud/%lud\n", | |
| 88 | + ialloc.bytes, conf.ialloc); | |
| 89 | + return nil; | |
| 90 | + } | |
| 91 | + setmalloctag(b, getcallerpc(&size)); | |
| 92 | + b->flag = BINTR; | |
| 93 | + | |
| 94 | + ilock(&ialloc.lk); | |
| 95 | + ialloc.bytes += b->lim - b->base; | |
| 96 | + iunlock(&ialloc.lk); | |
| 97 | + | |
| 98 | + return b; | |
| 99 | +} | |
| 100 | + | |
| 101 | +void | |
| 102 | +freeb(Block *b) | |
| 103 | +{ | |
| 104 | + void *dead = (void*)Bdead; | |
| 105 | + | |
| 106 | + if(b == nil) | |
| 107 | + return; | |
| 108 | + | |
| 109 | + /* | |
| 110 | + * drivers which perform non cache coherent DMA manage their own buffer | |
| 111 | + * pool of uncached buffers and provide their own free routine. | |
| 112 | + */ | |
| 113 | + if(b->free) { | |
| 114 | + b->free(b); | |
| 115 | + return; | |
| 116 | + } | |
| 117 | + if(b->flag & BINTR) { | |
| 118 | + ilock(&ialloc.lk); | |
| 119 | + ialloc.bytes -= b->lim - b->base; | |
| 120 | + iunlock(&ialloc.lk); | |
| 121 | + } | |
| 122 | + | |
| 123 | + /* poison the block in case someone is still holding onto it */ | |
| 124 | + b->next = dead; | |
| 125 | + b->rp = dead; | |
| 126 | + b->wp = dead; | |
| 127 | + b->lim = dead; | |
| 128 | + b->base = dead; | |
| 129 | + | |
| 130 | + free(b); | |
| 131 | +} | |
| 132 | + | |
| 133 | +void | |
| 134 | +checkb(Block *b, char *msg) | |
| 135 | +{ | |
| 136 | + void *dead = (void*)Bdead; | |
| 137 | + | |
| 138 | + if(b == dead) | |
| 139 | + panic("checkb b %s %lux", msg, b); | |
| 140 | + if(b->base == dead || b->lim == dead || b->next == dead | |
| 141 | + || b->rp == dead || b->wp == dead){ | |
| 142 | + print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n", | |
| 143 | + b->base, b->lim, b->next); | |
| 144 | + print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp); | |
| 145 | + panic("checkb dead: %s\n", msg); | |
| 146 | + } | |
| 147 | + | |
| 148 | + if(b->base > b->lim) | |
| 149 | + panic("checkb 0 %s %lux %lux", msg, b->base, b->lim); | |
| 150 | + if(b->rp < b->base) | |
| 151 | + panic("checkb 1 %s %lux %lux", msg, b->base, b->rp); | |
| 152 | + if(b->wp < b->base) | |
| 153 | + panic("checkb 2 %s %lux %lux", msg, b->base, b->wp); | |
| 154 | + if(b->rp > b->lim) | |
| 155 | + panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim); | |
| 156 | + if(b->wp > b->lim) | |
| 157 | + panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim); | |
| 158 | + | |
| 159 | +} | |
| 160 | + | |
| 161 | +void | |
| 162 | +iallocsummary(void) | |
| 163 | +{ | |
| 164 | + print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc); | |
| 165 | +} | |
| @@ -0,0 +1,46 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | + | |
| 8 | +void | |
| 9 | +cinit(void) | |
| 10 | +{ | |
| 11 | +} | |
| 12 | + | |
| 13 | +void | |
| 14 | +copen(Chan *c) | |
| 15 | +{ | |
| 16 | + USED(c); | |
| 17 | +} | |
| 18 | + | |
| 19 | +int | |
| 20 | +cread(Chan *c, uchar *buf, int len, vlong off) | |
| 21 | +{ | |
| 22 | + USED(c); | |
| 23 | + USED(buf); | |
| 24 | + USED(len); | |
| 25 | + USED(off); | |
| 26 | + | |
| 27 | + return 0; | |
| 28 | +} | |
| 29 | + | |
| 30 | +void | |
| 31 | +cupdate(Chan *c, uchar *buf, int len, vlong off) | |
| 32 | +{ | |
| 33 | + USED(c); | |
| 34 | + USED(buf); | |
| 35 | + USED(len); | |
| 36 | + USED(off); | |
| 37 | +} | |
| 38 | + | |
| 39 | +void | |
| 40 | +cwrite(Chan* c, uchar *buf, int len, vlong off) | |
| 41 | +{ | |
| 42 | + USED(c); | |
| 43 | + USED(buf); | |
| 44 | + USED(len); | |
| 45 | + USED(off); | |
| 46 | +} | |
| @@ -0,0 +1,1496 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +int chandebug=0; /* toggled by sysr1 */ | |
| 8 | +QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */ | |
| 9 | + | |
| 10 | +int domount(Chan**, Mhead**); | |
| 11 | + | |
| 12 | +void | |
| 13 | +dumpmount(void) /* DEBUGGING */ | |
| 14 | +{ | |
| 15 | + Pgrp *pg; | |
| 16 | + Mount *t; | |
| 17 | + Mhead **h, **he, *f; | |
| 18 | + | |
| 19 | + if(up == nil){ | |
| 20 | + print("no process for dumpmount\n"); | |
| 21 | + return; | |
| 22 | + } | |
| 23 | + pg = up->pgrp; | |
| 24 | + if(pg == nil){ | |
| 25 | + print("no pgrp for dumpmount\n"); | |
| 26 | + return; | |
| 27 | + } | |
| 28 | + rlock(&pg->ns); | |
| 29 | + if(waserror()) { | |
| 30 | + runlock(&pg->ns); | |
| 31 | + nexterror(); | |
| 32 | + } | |
| 33 | + | |
| 34 | + he = &pg->mnthash[MNTHASH]; | |
| 35 | + for(h = pg->mnthash; h < he; h++) { | |
| 36 | + for(f = *h; f; f = f->hash) { | |
| 37 | + print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f, | |
| 38 | + f->from->name->s, f->from->qid.path, | |
| 39 | + f->from->qid.vers, devtab[f->from->type]->dc, | |
| 40 | + f->from->dev); | |
| 41 | + for(t = f->mount; t; t = t->next) | |
| 42 | + print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev); | |
| 43 | + } | |
| 44 | + } | |
| 45 | + poperror(); | |
| 46 | + runlock(&pg->ns); | |
| 47 | +} | |
| 48 | + | |
| 49 | + | |
| 50 | +char* | |
| 51 | +c2name(Chan *c) /* DEBUGGING */ | |
| 52 | +{ | |
| 53 | + if(c == nil) | |
| 54 | + return "<nil chan>"; | |
| 55 | + if(c->name == nil) | |
| 56 | + return "<nil name>"; | |
| 57 | + if(c->name->s == nil) | |
| 58 | + return "<nil name.s>"; | |
| 59 | + return c->name->s; | |
| 60 | +} | |
| 61 | + | |
| 62 | +enum | |
| 63 | +{ | |
| 64 | + CNAMESLOP = 20 | |
| 65 | +}; | |
| 66 | + | |
| 67 | +struct | |
| 68 | +{ | |
| 69 | + Lock lk; | |
| 70 | + int fid; | |
| 71 | + Chan *free; | |
| 72 | + Chan *list; | |
| 73 | +}chanalloc; | |
| 74 | + | |
| 75 | +typedef struct Elemlist Elemlist; | |
| 76 | + | |
| 77 | +struct Elemlist | |
| 78 | +{ | |
| 79 | + char *name; /* copy of name, so '/' can be overwritten */ | |
| 80 | + int nelems; | |
| 81 | + char **elems; | |
| 82 | + int *off; | |
| 83 | + int mustbedir; | |
| 84 | +}; | |
| 85 | + | |
| 86 | +#define SEP(c) ((c) == 0 || (c) == '/') | |
| 87 | +void cleancname(Cname*); | |
| 88 | + | |
| 89 | +int | |
| 90 | +isdotdot(char *p) | |
| 91 | +{ | |
| 92 | + return p[0]=='.' && p[1]=='.' && p[2]=='\0'; | |
| 93 | +} | |
| 94 | + | |
| 95 | +int | |
| 96 | +incref(Ref *r) | |
| 97 | +{ | |
| 98 | + int x; | |
| 99 | + | |
| 100 | + lock(&r->lk); | |
| 101 | + x = ++r->ref; | |
| 102 | + unlock(&r->lk); | |
| 103 | + return x; | |
| 104 | +} | |
| 105 | + | |
| 106 | +int | |
| 107 | +decref(Ref *r) | |
| 108 | +{ | |
| 109 | + int x; | |
| 110 | + | |
| 111 | + lock(&r->lk); | |
| 112 | + x = --r->ref; | |
| 113 | + unlock(&r->lk); | |
| 114 | + if(x < 0) | |
| 115 | + panic("decref, pc=0x%lux", getcallerpc(&r)); | |
| 116 | + | |
| 117 | + return x; | |
| 118 | +} | |
| 119 | + | |
| 120 | +/* | |
| 121 | + * Rather than strncpy, which zeros the rest of the buffer, kstrcpy | |
| 122 | + * truncates if necessary, always zero terminates, does not zero fill, | |
| 123 | + * and puts ... at the end of the string if it's too long. Usually used to | |
| 124 | + * save a string in up->genbuf; | |
| 125 | + */ | |
| 126 | +void | |
| 127 | +kstrcpy(char *s, char *t, int ns) | |
| 128 | +{ | |
| 129 | + int nt; | |
| 130 | + | |
| 131 | + nt = strlen(t); | |
| 132 | + if(nt+1 <= ns){ | |
| 133 | + memmove(s, t, nt+1); | |
| 134 | + return; | |
| 135 | + } | |
| 136 | + /* too long */ | |
| 137 | + if(ns < 4){ | |
| 138 | + /* but very short! */ | |
| 139 | + strncpy(s, t, ns); | |
| 140 | + return; | |
| 141 | + } | |
| 142 | + /* truncate with ... at character boundary (very rare case) */ | |
| 143 | + memmove(s, t, ns-4); | |
| 144 | + ns -= 4; | |
| 145 | + s[ns] = '\0'; | |
| 146 | + /* look for first byte of UTF-8 sequence by skipping continuation bytes */ | |
| 147 | + while(ns>0 && (s[--ns]&0xC0)==0x80) | |
| 148 | + ; | |
| 149 | + strcpy(s+ns, "..."); | |
| 150 | +} | |
| 151 | + | |
| 152 | +int | |
| 153 | +emptystr(char *s) | |
| 154 | +{ | |
| 155 | + if(s == nil) | |
| 156 | + return 1; | |
| 157 | + if(s[0] == '\0') | |
| 158 | + return 1; | |
| 159 | + return 0; | |
| 160 | +} | |
| 161 | + | |
| 162 | +/* | |
| 163 | + * Atomically replace *p with copy of s | |
| 164 | + */ | |
| 165 | +void | |
| 166 | +kstrdup(char **p, char *s) | |
| 167 | +{ | |
| 168 | + int n; | |
| 169 | + char *t, *prev; | |
| 170 | + static Lock l; | |
| 171 | + | |
| 172 | + n = strlen(s)+1; | |
| 173 | + /* if it's a user, we can wait for memory; if not, something's very wrong */ | |
| 174 | + if(up){ | |
| 175 | + t = smalloc(n); | |
| 176 | + setmalloctag(t, getcallerpc(&p)); | |
| 177 | + }else{ | |
| 178 | + t = malloc(n); | |
| 179 | + if(t == nil) | |
| 180 | + panic("kstrdup: no memory"); | |
| 181 | + } | |
| 182 | + memmove(t, s, n); | |
| 183 | + prev = *p; | |
| 184 | + *p = t; | |
| 185 | + free(prev); | |
| 186 | +} | |
| 187 | + | |
| 188 | +void | |
| 189 | +chandevreset(void) | |
| 190 | +{ | |
| 191 | + int i; | |
| 192 | + | |
| 193 | + for(i=0; devtab[i] != nil; i++) | |
| 194 | + devtab[i]->reset(); | |
| 195 | +} | |
| 196 | + | |
| 197 | +void | |
| 198 | +chandevinit(void) | |
| 199 | +{ | |
| 200 | + int i; | |
| 201 | + | |
| 202 | + for(i=0; devtab[i] != nil; i++) | |
| 203 | + devtab[i]->init(); | |
| 204 | +} | |
| 205 | + | |
| 206 | +void | |
| 207 | +chandevshutdown(void) | |
| 208 | +{ | |
| 209 | + int i; | |
| 210 | + | |
| 211 | + /* shutdown in reverse order */ | |
| 212 | + for(i=0; devtab[i] != nil; i++) | |
| 213 | + ; | |
| 214 | + for(i--; i >= 0; i--) | |
| 215 | + devtab[i]->shutdown(); | |
| 216 | +} | |
| 217 | + | |
| 218 | +Chan* | |
| 219 | +newchan(void) | |
| 220 | +{ | |
| 221 | + Chan *c; | |
| 222 | + | |
| 223 | + lock(&chanalloc.lk); | |
| 224 | + c = chanalloc.free; | |
| 225 | + if(c != 0) | |
| 226 | + chanalloc.free = c->next; | |
| 227 | + unlock(&chanalloc.lk); | |
| 228 | + | |
| 229 | + if(c == nil) { | |
| 230 | + c = smalloc(sizeof(Chan)); | |
| 231 | + lock(&chanalloc.lk); | |
| 232 | + c->fid = ++chanalloc.fid; | |
| 233 | + c->link = chanalloc.list; | |
| 234 | + chanalloc.list = c; | |
| 235 | + unlock(&chanalloc.lk); | |
| 236 | + } | |
| 237 | + | |
| 238 | + /* if you get an error before associating with a dev, | |
| 239 | + close calls rootclose, a nop */ | |
| 240 | + c->type = 0; | |
| 241 | + c->flag = 0; | |
| 242 | + c->ref.ref = 1; | |
| 243 | + c->dev = 0; | |
| 244 | + c->offset = 0; | |
| 245 | + c->iounit = 0; | |
| 246 | + c->umh = 0; | |
| 247 | + c->uri = 0; | |
| 248 | + c->dri = 0; | |
| 249 | + c->aux = 0; | |
| 250 | + c->mchan = 0; | |
| 251 | + c->mcp = 0; | |
| 252 | + c->mux = 0; | |
| 253 | + memset(&c->mqid, 0, sizeof(c->mqid)); | |
| 254 | + c->name = 0; | |
| 255 | + return c; | |
| 256 | +} | |
| 257 | + | |
| 258 | +static Ref ncname; | |
| 259 | + | |
| 260 | +Cname* | |
| 261 | +newcname(char *s) | |
| 262 | +{ | |
| 263 | + Cname *n; | |
| 264 | + int i; | |
| 265 | + | |
| 266 | + n = smalloc(sizeof(Cname)); | |
| 267 | + i = strlen(s); | |
| 268 | + n->len = i; | |
| 269 | + n->alen = i+CNAMESLOP; | |
| 270 | + n->s = smalloc(n->alen); | |
| 271 | + memmove(n->s, s, i+1); | |
| 272 | + n->ref.ref = 1; | |
| 273 | + incref(&ncname); | |
| 274 | + return n; | |
| 275 | +} | |
| 276 | + | |
| 277 | +void | |
| 278 | +cnameclose(Cname *n) | |
| 279 | +{ | |
| 280 | + if(n == nil) | |
| 281 | + return; | |
| 282 | + if(decref(&n->ref)) | |
| 283 | + return; | |
| 284 | + decref(&ncname); | |
| 285 | + free(n->s); | |
| 286 | + free(n); | |
| 287 | +} | |
| 288 | + | |
| 289 | +Cname* | |
| 290 | +addelem(Cname *n, char *s) | |
| 291 | +{ | |
| 292 | + int i, a; | |
| 293 | + char *t; | |
| 294 | + Cname *new; | |
| 295 | + | |
| 296 | + if(s[0]=='.' && s[1]=='\0') | |
| 297 | + return n; | |
| 298 | + | |
| 299 | + if(n->ref.ref > 1){ | |
| 300 | + /* copy on write */ | |
| 301 | + new = newcname(n->s); | |
| 302 | + cnameclose(n); | |
| 303 | + n = new; | |
| 304 | + } | |
| 305 | + | |
| 306 | + i = strlen(s); | |
| 307 | + if(n->len+1+i+1 > n->alen){ | |
| 308 | + a = n->len+1+i+1 + CNAMESLOP; | |
| 309 | + t = smalloc(a); | |
| 310 | + memmove(t, n->s, n->len+1); | |
| 311 | + free(n->s); | |
| 312 | + n->s = t; | |
| 313 | + n->alen = a; | |
| 314 | + } | |
| 315 | + if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */ | |
| 316 | + n->s[n->len++] = '/'; | |
| 317 | + memmove(n->s+n->len, s, i+1); | |
| 318 | + n->len += i; | |
| 319 | + if(isdotdot(s)) | |
| 320 | + cleancname(n); | |
| 321 | + return n; | |
| 322 | +} | |
| 323 | + | |
| 324 | +void | |
| 325 | +chanfree(Chan *c) | |
| 326 | +{ | |
| 327 | + c->flag = CFREE; | |
| 328 | + | |
| 329 | + if(c->umh != nil){ | |
| 330 | + putmhead(c->umh); | |
| 331 | + c->umh = nil; | |
| 332 | + } | |
| 333 | + if(c->umc != nil){ | |
| 334 | + cclose(c->umc); | |
| 335 | + c->umc = nil; | |
| 336 | + } | |
| 337 | + if(c->mux != nil){ | |
| 338 | + muxclose(c->mux); | |
| 339 | + c->mux = nil; | |
| 340 | + } | |
| 341 | + if(c->mchan != nil){ | |
| 342 | + cclose(c->mchan); | |
| 343 | + c->mchan = nil; | |
| 344 | + } | |
| 345 | + | |
| 346 | + cnameclose(c->name); | |
| 347 | + | |
| 348 | + lock(&chanalloc.lk); | |
| 349 | + c->next = chanalloc.free; | |
| 350 | + chanalloc.free = c; | |
| 351 | + unlock(&chanalloc.lk); | |
| 352 | +} | |
| 353 | + | |
| 354 | +void | |
| 355 | +cclose(Chan *c) | |
| 356 | +{ | |
| 357 | + if(c->flag&CFREE) | |
| 358 | + panic("cclose %lux", getcallerpc(&c)); | |
| 359 | + | |
| 360 | + if(decref(&c->ref)) | |
| 361 | + return; | |
| 362 | + | |
| 363 | + if(!waserror()){ | |
| 364 | + devtab[c->type]->close(c); | |
| 365 | + poperror(); | |
| 366 | + } | |
| 367 | + chanfree(c); | |
| 368 | +} | |
| 369 | + | |
| 370 | +/* | |
| 371 | + * Make sure we have the only copy of c. (Copy on write.) | |
| 372 | + */ | |
| 373 | +Chan* | |
| 374 | +cunique(Chan *c) | |
| 375 | +{ | |
| 376 | + Chan *nc; | |
| 377 | + | |
| 378 | + if(c->ref.ref != 1) { | |
| 379 | + nc = cclone(c); | |
| 380 | + cclose(c); | |
| 381 | + c = nc; | |
| 382 | + } | |
| 383 | + | |
| 384 | + return c; | |
| 385 | +} | |
| 386 | + | |
| 387 | +int | |
| 388 | +eqqid(Qid a, Qid b) | |
| 389 | +{ | |
| 390 | + return a.path==b.path && a.vers==b.vers; | |
| 391 | +} | |
| 392 | + | |
| 393 | +int | |
| 394 | +eqchan(Chan *a, Chan *b, int pathonly) | |
| 395 | +{ | |
| 396 | + if(a->qid.path != b->qid.path) | |
| 397 | + return 0; | |
| 398 | + if(!pathonly && a->qid.vers!=b->qid.vers) | |
| 399 | + return 0; | |
| 400 | + if(a->type != b->type) | |
| 401 | + return 0; | |
| 402 | + if(a->dev != b->dev) | |
| 403 | + return 0; | |
| 404 | + return 1; | |
| 405 | +} | |
| 406 | + | |
| 407 | +int | |
| 408 | +eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly) | |
| 409 | +{ | |
| 410 | + if(a->qid.path != qid.path) | |
| 411 | + return 0; | |
| 412 | + if(!pathonly && a->qid.vers!=qid.vers) | |
| 413 | + return 0; | |
| 414 | + if(a->type != type) | |
| 415 | + return 0; | |
| 416 | + if(a->dev != dev) | |
| 417 | + return 0; | |
| 418 | + return 1; | |
| 419 | +} | |
| 420 | + | |
| 421 | +Mhead* | |
| 422 | +newmhead(Chan *from) | |
| 423 | +{ | |
| 424 | + Mhead *mh; | |
| 425 | + | |
| 426 | + mh = smalloc(sizeof(Mhead)); | |
| 427 | + mh->ref.ref = 1; | |
| 428 | + mh->from = from; | |
| 429 | + incref(&from->ref); | |
| 430 | + | |
| 431 | +/* | |
| 432 | + n = from->name->len; | |
| 433 | + if(n >= sizeof(mh->fromname)) | |
| 434 | + n = sizeof(mh->fromname)-1; | |
| 435 | + memmove(mh->fromname, from->name->s, n); | |
| 436 | + mh->fromname[n] = 0; | |
| 437 | +*/ | |
| 438 | + return mh; | |
| 439 | +} | |
| 440 | + | |
| 441 | +int | |
| 442 | +cmount(Chan **newp, Chan *old, int flag, char *spec) | |
| 443 | +{ | |
| 444 | + Pgrp *pg; | |
| 445 | + int order, flg; | |
| 446 | + Mhead *m, **l, *mh; | |
| 447 | + Mount *nm, *f, *um, **h; | |
| 448 | + Chan *new; | |
| 449 | + | |
| 450 | + if(QTDIR & (old->qid.type^(*newp)->qid.type)) | |
| 451 | + error(Emount); | |
| 452 | + | |
| 453 | +if(old->umh)print("cmount old extra umh\n"); | |
| 454 | + | |
| 455 | + order = flag&MORDER; | |
| 456 | + | |
| 457 | + if((old->qid.type&QTDIR)==0 && order != MREPL) | |
| 458 | + error(Emount); | |
| 459 | + | |
| 460 | + new = *newp; | |
| 461 | + mh = new->umh; | |
| 462 | + | |
| 463 | + /* | |
| 464 | + * Not allowed to bind when the old directory | |
| 465 | + * is itself a union. (Maybe it should be allowed, but I don't see | |
| 466 | + * what the semantics would be.) | |
| 467 | + * | |
| 468 | + * We need to check mh->mount->next to tell unions apart from | |
| 469 | + * simple mount points, so that things like | |
| 470 | + * mount -c fd /root | |
| 471 | + * bind -c /root / | |
| 472 | + * work. The check of mount->mflag catches things like | |
| 473 | + * mount fd /root | |
| 474 | + * bind -c /root / | |
| 475 | + * | |
| 476 | + * This is far more complicated than it should be, but I don't | |
| 477 | + * see an easier way at the moment. -rsc | |
| 478 | + */ | |
| 479 | + if((flag&MCREATE) && mh && mh->mount | |
| 480 | + && (mh->mount->next || !(mh->mount->mflag&MCREATE))) | |
| 481 | + error(Emount); | |
| 482 | + | |
| 483 | + pg = up->pgrp; | |
| 484 | + wlock(&pg->ns); | |
| 485 | + | |
| 486 | + l = &MOUNTH(pg, old->qid); | |
| 487 | + for(m = *l; m; m = m->hash) { | |
| 488 | + if(eqchan(m->from, old, 1)) | |
| 489 | + break; | |
| 490 | + l = &m->hash; | |
| 491 | + } | |
| 492 | + | |
| 493 | + if(m == nil) { | |
| 494 | + /* | |
| 495 | + * nothing mounted here yet. create a mount | |
| 496 | + * head and add to the hash table. | |
| 497 | + */ | |
| 498 | + m = newmhead(old); | |
| 499 | + *l = m; | |
| 500 | + | |
| 501 | + /* | |
| 502 | + * if this is a union mount, add the old | |
| 503 | + * node to the mount chain. | |
| 504 | + */ | |
| 505 | + if(order != MREPL) | |
| 506 | + m->mount = newmount(m, old, 0, 0); | |
| 507 | + } | |
| 508 | + wlock(&m->lock); | |
| 509 | + if(waserror()){ | |
| 510 | + wunlock(&m->lock); | |
| 511 | + nexterror(); | |
| 512 | + } | |
| 513 | + wunlock(&pg->ns); | |
| 514 | + | |
| 515 | + nm = newmount(m, new, flag, spec); | |
| 516 | + if(mh != nil && mh->mount != nil) { | |
| 517 | + /* | |
| 518 | + * copy a union when binding it onto a directory | |
| 519 | + */ | |
| 520 | + flg = order; | |
| 521 | + if(order == MREPL) | |
| 522 | + flg = MAFTER; | |
| 523 | + h = &nm->next; | |
| 524 | + um = mh->mount; | |
| 525 | + for(um = um->next; um; um = um->next) { | |
| 526 | + f = newmount(m, um->to, flg, um->spec); | |
| 527 | + *h = f; | |
| 528 | + h = &f->next; | |
| 529 | + } | |
| 530 | + } | |
| 531 | + | |
| 532 | + if(m->mount && order == MREPL) { | |
| 533 | + mountfree(m->mount); | |
| 534 | + m->mount = 0; | |
| 535 | + } | |
| 536 | + | |
| 537 | + if(flag & MCREATE) | |
| 538 | + nm->mflag |= MCREATE; | |
| 539 | + | |
| 540 | + if(m->mount && order == MAFTER) { | |
| 541 | + for(f = m->mount; f->next; f = f->next) | |
| 542 | + ; | |
| 543 | + f->next = nm; | |
| 544 | + } | |
| 545 | + else { | |
| 546 | + for(f = nm; f->next; f = f->next) | |
| 547 | + ; | |
| 548 | + f->next = m->mount; | |
| 549 | + m->mount = nm; | |
| 550 | + } | |
| 551 | + | |
| 552 | + wunlock(&m->lock); | |
| 553 | + poperror(); | |
| 554 | + return nm->mountid; | |
| 555 | +} | |
| 556 | + | |
| 557 | +void | |
| 558 | +cunmount(Chan *mnt, Chan *mounted) | |
| 559 | +{ | |
| 560 | + Pgrp *pg; | |
| 561 | + Mhead *m, **l; | |
| 562 | + Mount *f, **p; | |
| 563 | + | |
| 564 | + if(mnt->umh) /* should not happen */ | |
| 565 | + print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh); | |
| 566 | + | |
| 567 | + /* | |
| 568 | + * It _can_ happen that mounted->umh is non-nil, | |
| 569 | + * because mounted is the result of namec(Aopen) | |
| 570 | + * (see sysfile.c:/^sysunmount). | |
| 571 | + * If we open a union directory, it will have a umh. | |
| 572 | + * Although surprising, this is okay, since the | |
| 573 | + * cclose will take care of freeing the umh. | |
| 574 | + */ | |
| 575 | + | |
| 576 | + pg = up->pgrp; | |
| 577 | + wlock(&pg->ns); | |
| 578 | + | |
| 579 | + l = &MOUNTH(pg, mnt->qid); | |
| 580 | + for(m = *l; m; m = m->hash) { | |
| 581 | + if(eqchan(m->from, mnt, 1)) | |
| 582 | + break; | |
| 583 | + l = &m->hash; | |
| 584 | + } | |
| 585 | + | |
| 586 | + if(m == 0) { | |
| 587 | + wunlock(&pg->ns); | |
| 588 | + error(Eunmount); | |
| 589 | + } | |
| 590 | + | |
| 591 | + wlock(&m->lock); | |
| 592 | + if(mounted == 0) { | |
| 593 | + *l = m->hash; | |
| 594 | + wunlock(&pg->ns); | |
| 595 | + mountfree(m->mount); | |
| 596 | + m->mount = nil; | |
| 597 | + cclose(m->from); | |
| 598 | + wunlock(&m->lock); | |
| 599 | + putmhead(m); | |
| 600 | + return; | |
| 601 | + } | |
| 602 | + | |
| 603 | + p = &m->mount; | |
| 604 | + for(f = *p; f; f = f->next) { | |
| 605 | + /* BUG: Needs to be 2 pass */ | |
| 606 | + if(eqchan(f->to, mounted, 1) || | |
| 607 | + (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) { | |
| 608 | + *p = f->next; | |
| 609 | + f->next = 0; | |
| 610 | + mountfree(f); | |
| 611 | + if(m->mount == nil) { | |
| 612 | + *l = m->hash; | |
| 613 | + cclose(m->from); | |
| 614 | + wunlock(&m->lock); | |
| 615 | + wunlock(&pg->ns); | |
| 616 | + putmhead(m); | |
| 617 | + return; | |
| 618 | + } | |
| 619 | + wunlock(&m->lock); | |
| 620 | + wunlock(&pg->ns); | |
| 621 | + return; | |
| 622 | + } | |
| 623 | + p = &f->next; | |
| 624 | + } | |
| 625 | + wunlock(&m->lock); | |
| 626 | + wunlock(&pg->ns); | |
| 627 | + error(Eunion); | |
| 628 | +} | |
| 629 | + | |
| 630 | +Chan* | |
| 631 | +cclone(Chan *c) | |
| 632 | +{ | |
| 633 | + Chan *nc; | |
| 634 | + Walkqid *wq; | |
| 635 | + | |
| 636 | + wq = devtab[c->type]->walk(c, nil, nil, 0); | |
| 637 | + if(wq == nil) | |
| 638 | + error("clone failed"); | |
| 639 | + nc = wq->clone; | |
| 640 | + free(wq); | |
| 641 | + nc->name = c->name; | |
| 642 | + if(c->name) | |
| 643 | + incref(&c->name->ref); | |
| 644 | + return nc; | |
| 645 | +} | |
| 646 | + | |
| 647 | +int | |
| 648 | +findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid) | |
| 649 | +{ | |
| 650 | + Pgrp *pg; | |
| 651 | + Mhead *m; | |
| 652 | + | |
| 653 | + pg = up->pgrp; | |
| 654 | + rlock(&pg->ns); | |
| 655 | + for(m = MOUNTH(pg, qid); m; m = m->hash){ | |
| 656 | + rlock(&m->lock); | |
| 657 | +if(m->from == nil){ | |
| 658 | + print("m %p m->from 0\n", m); | |
| 659 | + runlock(&m->lock); | |
| 660 | + continue; | |
| 661 | +} | |
| 662 | + if(eqchantdqid(m->from, type, dev, qid, 1)) { | |
| 663 | + runlock(&pg->ns); | |
| 664 | + if(mp != nil){ | |
| 665 | + incref(&m->ref); | |
| 666 | + if(*mp != nil) | |
| 667 | + putmhead(*mp); | |
| 668 | + *mp = m; | |
| 669 | + } | |
| 670 | + if(*cp != nil) | |
| 671 | + cclose(*cp); | |
| 672 | + incref(&m->mount->to->ref); | |
| 673 | + *cp = m->mount->to; | |
| 674 | + runlock(&m->lock); | |
| 675 | + return 1; | |
| 676 | + } | |
| 677 | + runlock(&m->lock); | |
| 678 | + } | |
| 679 | + | |
| 680 | + runlock(&pg->ns); | |
| 681 | + return 0; | |
| 682 | +} | |
| 683 | + | |
| 684 | +int | |
| 685 | +domount(Chan **cp, Mhead **mp) | |
| 686 | +{ | |
| 687 | + return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid); | |
| 688 | +} | |
| 689 | + | |
| 690 | +Chan* | |
| 691 | +undomount(Chan *c, Cname *name) | |
| 692 | +{ | |
| 693 | + Chan *nc; | |
| 694 | + Pgrp *pg; | |
| 695 | + Mount *t; | |
| 696 | + Mhead **h, **he, *f; | |
| 697 | + | |
| 698 | + pg = up->pgrp; | |
| 699 | + rlock(&pg->ns); | |
| 700 | + if(waserror()) { | |
| 701 | + runlock(&pg->ns); | |
| 702 | + nexterror(); | |
| 703 | + } | |
| 704 | + | |
| 705 | + he = &pg->mnthash[MNTHASH]; | |
| 706 | + for(h = pg->mnthash; h < he; h++) { | |
| 707 | + for(f = *h; f; f = f->hash) { | |
| 708 | + if(strcmp(f->from->name->s, name->s) != 0) | |
| 709 | + continue; | |
| 710 | + for(t = f->mount; t; t = t->next) { | |
| 711 | + if(eqchan(c, t->to, 1)) { | |
| 712 | + /* | |
| 713 | + * We want to come out on the left hand side of the mount | |
| 714 | + * point using the element of the union that we entered on. | |
| 715 | + * To do this, find the element that has a from name of | |
| 716 | + * c->name->s. | |
| 717 | + */ | |
| 718 | + if(strcmp(t->head->from->name->s, name->s) != 0) | |
| 719 | + continue; | |
| 720 | + nc = t->head->from; | |
| 721 | + incref(&nc->ref); | |
| 722 | + cclose(c); | |
| 723 | + c = nc; | |
| 724 | + break; | |
| 725 | + } | |
| 726 | + } | |
| 727 | + } | |
| 728 | + } | |
| 729 | + poperror(); | |
| 730 | + runlock(&pg->ns); | |
| 731 | + return c; | |
| 732 | +} | |
| 733 | + | |
| 734 | +/* | |
| 735 | + * Either walks all the way or not at all. No partial results in *cp. | |
| 736 | + * *nerror is the number of names to display in an error message. | |
| 737 | + */ | |
| 738 | +static char Edoesnotexist[] = "does not exist"; | |
| 739 | +int | |
| 740 | +walk(Chan **cp, char **names, int nnames, int nomount, int *nerror) | |
| 741 | +{ | |
| 742 | + int dev, dotdot, i, n, nhave, ntry, type; | |
| 743 | + Chan *c, *nc; | |
| 744 | + Cname *cname; | |
| 745 | + Mount *f; | |
| 746 | + Mhead *mh, *nmh; | |
| 747 | + Walkqid *wq; | |
| 748 | + | |
| 749 | + c = *cp; | |
| 750 | + incref(&c->ref); | |
| 751 | + cname = c->name; | |
| 752 | + incref(&cname->ref); | |
| 753 | + mh = nil; | |
| 754 | + | |
| 755 | + /* | |
| 756 | + * While we haven't gotten all the way down the path: | |
| 757 | + * 1. step through a mount point, if any | |
| 758 | + * 2. send a walk request for initial dotdot or initial prefix without dotdot | |
| 759 | + * 3. move to the first mountpoint along the way. | |
| 760 | + * 4. repeat. | |
| 761 | + * | |
| 762 | + * An invariant is that each time through the loop, c is on the undomount | |
| 763 | + * side of the mount point, and c's name is cname. | |
| 764 | + */ | |
| 765 | + for(nhave=0; nhave<nnames; nhave+=n){ | |
| 766 | + if((c->qid.type&QTDIR)==0){ | |
| 767 | + if(nerror) | |
| 768 | + *nerror = nhave; | |
| 769 | + cnameclose(cname); | |
| 770 | + cclose(c); | |
| 771 | + strcpy(up->errstr, Enotdir); | |
| 772 | + if(mh != nil) | |
| 773 | +{print("walk 1\n"); | |
| 774 | + putmhead(mh); | |
| 775 | +} | |
| 776 | + return -1; | |
| 777 | + } | |
| 778 | + ntry = nnames - nhave; | |
| 779 | + if(ntry > MAXWELEM) | |
| 780 | + ntry = MAXWELEM; | |
| 781 | + dotdot = 0; | |
| 782 | + for(i=0; i<ntry; i++){ | |
| 783 | + if(isdotdot(names[nhave+i])){ | |
| 784 | + if(i==0) { | |
| 785 | + dotdot = 1; | |
| 786 | + ntry = 1; | |
| 787 | + } else | |
| 788 | + ntry = i; | |
| 789 | + break; | |
| 790 | + } | |
| 791 | + } | |
| 792 | + | |
| 793 | + if(!dotdot && !nomount) | |
| 794 | + domount(&c, &mh); | |
| 795 | + | |
| 796 | + type = c->type; | |
| 797 | + dev = c->dev; | |
| 798 | + | |
| 799 | + if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){ | |
| 800 | + /* try a union mount, if any */ | |
| 801 | + if(mh && !nomount){ | |
| 802 | + /* | |
| 803 | + * mh->mount == c, so start at mh->mount->next | |
| 804 | + */ | |
| 805 | + rlock(&mh->lock); | |
| 806 | + for(f = mh->mount->next; f; f = f->next) | |
| 807 | + if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil) | |
| 808 | + break; | |
| 809 | + runlock(&mh->lock); | |
| 810 | + if(f != nil){ | |
| 811 | + type = f->to->type; | |
| 812 | + dev = f->to->dev; | |
| 813 | + } | |
| 814 | + } | |
| 815 | + if(wq == nil){ | |
| 816 | + cclose(c); | |
| 817 | + cnameclose(cname); | |
| 818 | + if(nerror) | |
| 819 | + *nerror = nhave+1; | |
| 820 | + if(mh != nil) | |
| 821 | + putmhead(mh); | |
| 822 | + return -1; | |
| 823 | + } | |
| 824 | + } | |
| 825 | + | |
| 826 | + nmh = nil; | |
| 827 | + if(dotdot) { | |
| 828 | + assert(wq->nqid == 1); | |
| 829 | + assert(wq->clone != nil); | |
| 830 | + | |
| 831 | + cname = addelem(cname, ".."); | |
| 832 | + nc = undomount(wq->clone, cname); | |
| 833 | + n = 1; | |
| 834 | + } else { | |
| 835 | + nc = nil; | |
| 836 | + if(!nomount) | |
| 837 | + for(i=0; i<wq->nqid && i<ntry-1; i++) | |
| 838 | + if(findmount(&nc, &nmh, type, dev, wq->qid[i])) | |
| 839 | + break; | |
| 840 | + if(nc == nil){ /* no mount points along path */ | |
| 841 | + if(wq->clone == nil){ | |
| 842 | + cclose(c); | |
| 843 | + cnameclose(cname); | |
| 844 | + if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){ | |
| 845 | + if(nerror) | |
| 846 | + *nerror = nhave+wq->nqid+1; | |
| 847 | + strcpy(up->errstr, Edoesnotexist); | |
| 848 | + }else{ | |
| 849 | + if(nerror) | |
| 850 | + *nerror = nhave+wq->nqid; | |
| 851 | + strcpy(up->errstr, Enotdir); | |
| 852 | + } | |
| 853 | + free(wq); | |
| 854 | + if(mh != nil) | |
| 855 | + putmhead(mh); | |
| 856 | + return -1; | |
| 857 | + } | |
| 858 | + n = wq->nqid; | |
| 859 | + nc = wq->clone; | |
| 860 | + }else{ /* stopped early, at a mount point */ | |
| 861 | + if(wq->clone != nil){ | |
| 862 | + cclose(wq->clone); | |
| 863 | + wq->clone = nil; | |
| 864 | + } | |
| 865 | + n = i+1; | |
| 866 | + } | |
| 867 | + for(i=0; i<n; i++) | |
| 868 | + cname = addelem(cname, names[nhave+i]); | |
| 869 | + } | |
| 870 | + cclose(c); | |
| 871 | + c = nc; | |
| 872 | + putmhead(mh); | |
| 873 | + mh = nmh; | |
| 874 | + free(wq); | |
| 875 | + } | |
| 876 | + | |
| 877 | + putmhead(mh); | |
| 878 | + | |
| 879 | + c = cunique(c); | |
| 880 | + | |
| 881 | + if(c->umh != nil){ //BUG | |
| 882 | + print("walk umh\n"); | |
| 883 | + putmhead(c->umh); | |
| 884 | + c->umh = nil; | |
| 885 | + } | |
| 886 | + | |
| 887 | + cnameclose(c->name); | |
| 888 | + c->name = cname; | |
| 889 | + | |
| 890 | + cclose(*cp); | |
| 891 | + *cp = c; | |
| 892 | + if(nerror) | |
| 893 | + *nerror = 0; | |
| 894 | + return 0; | |
| 895 | +} | |
| 896 | + | |
| 897 | +/* | |
| 898 | + * c is a mounted non-creatable directory. find a creatable one. | |
| 899 | + */ | |
| 900 | +Chan* | |
| 901 | +createdir(Chan *c, Mhead *m) | |
| 902 | +{ | |
| 903 | + Chan *nc; | |
| 904 | + Mount *f; | |
| 905 | + | |
| 906 | + rlock(&m->lock); | |
| 907 | + if(waserror()) { | |
| 908 | + runlock(&m->lock); | |
| 909 | + nexterror(); | |
| 910 | + } | |
| 911 | + for(f = m->mount; f; f = f->next) { | |
| 912 | + if(f->mflag&MCREATE) { | |
| 913 | + nc = cclone(f->to); | |
| 914 | + runlock(&m->lock); | |
| 915 | + poperror(); | |
| 916 | + cclose(c); | |
| 917 | + return nc; | |
| 918 | + } | |
| 919 | + } | |
| 920 | + error(Enocreate); | |
| 921 | + return 0; | |
| 922 | +} | |
| 923 | + | |
| 924 | +void | |
| 925 | +saveregisters(void) | |
| 926 | +{ | |
| 927 | +} | |
| 928 | + | |
| 929 | +/* | |
| 930 | + * In place, rewrite name to compress multiple /, eliminate ., and process .. | |
| 931 | + */ | |
| 932 | +void | |
| 933 | +cleancname(Cname *n) | |
| 934 | +{ | |
| 935 | + char *p; | |
| 936 | + | |
| 937 | + if(n->s[0] == '#'){ | |
| 938 | + p = strchr(n->s, '/'); | |
| 939 | + if(p == nil) | |
| 940 | + return; | |
| 941 | + cleanname(p); | |
| 942 | + | |
| 943 | + /* | |
| 944 | + * The correct name is #i rather than #i/, | |
| 945 | + * but the correct name of #/ is #/. | |
| 946 | + */ | |
| 947 | + if(strcmp(p, "/")==0 && n->s[1] != '/') | |
| 948 | + *p = '\0'; | |
| 949 | + }else | |
| 950 | + cleanname(n->s); | |
| 951 | + n->len = strlen(n->s); | |
| 952 | +} | |
| 953 | + | |
| 954 | +static void | |
| 955 | +growparse(Elemlist *e) | |
| 956 | +{ | |
| 957 | + char **new; | |
| 958 | + int *inew; | |
| 959 | + enum { Delta = 8 }; | |
| 960 | + | |
| 961 | + if(e->nelems % Delta == 0){ | |
| 962 | + new = smalloc((e->nelems+Delta) * sizeof(char*)); | |
| 963 | + memmove(new, e->elems, e->nelems*sizeof(char*)); | |
| 964 | + free(e->elems); | |
| 965 | + e->elems = new; | |
| 966 | + inew = smalloc((e->nelems+Delta+1) * sizeof(int)); | |
| 967 | + memmove(inew, e->off, e->nelems*sizeof(int)); | |
| 968 | + free(e->off); | |
| 969 | + e->off = inew; | |
| 970 | + } | |
| 971 | +} | |
| 972 | + | |
| 973 | +/* | |
| 974 | + * The name is known to be valid. | |
| 975 | + * Copy the name so slashes can be overwritten. | |
| 976 | + * An empty string will set nelem=0. | |
| 977 | + * A path ending in / or /. or /.//./ etc. will have | |
| 978 | + * e.mustbedir = 1, so that we correctly | |
| 979 | + * reject, e.g., "/adm/users/." when /adm/users is a file | |
| 980 | + * rather than a directory. | |
| 981 | + */ | |
| 982 | +static void | |
| 983 | +parsename(char *name, Elemlist *e) | |
| 984 | +{ | |
| 985 | + char *slash; | |
| 986 | + | |
| 987 | + kstrdup(&e->name, name); | |
| 988 | + name = e->name; | |
| 989 | + e->nelems = 0; | |
| 990 | + e->elems = nil; | |
| 991 | + e->off = smalloc(sizeof(int)); | |
| 992 | + e->off[0] = skipslash(name) - name; | |
| 993 | + for(;;){ | |
| 994 | + name = skipslash(name); | |
| 995 | + if(*name=='\0'){ | |
| 996 | + e->mustbedir = 1; | |
| 997 | + break; | |
| 998 | + } | |
| 999 | + growparse(e); | |
| 1000 | + e->elems[e->nelems++] = name; | |
| 1001 | + slash = utfrune(name, '/'); | |
| 1002 | + if(slash == nil){ | |
| 1003 | + e->off[e->nelems] = name+strlen(name) - e->name; | |
| 1004 | + e->mustbedir = 0; | |
| 1005 | + break; | |
| 1006 | + } | |
| 1007 | + e->off[e->nelems] = slash - e->name; | |
| 1008 | + *slash++ = '\0'; | |
| 1009 | + name = slash; | |
| 1010 | + } | |
| 1011 | +} | |
| 1012 | + | |
| 1013 | +void* | |
| 1014 | +memrchr(void *va, int c, long n) | |
| 1015 | +{ | |
| 1016 | + uchar *a, *e; | |
| 1017 | + | |
| 1018 | + a = va; | |
| 1019 | + for(e=a+n-1; e>a; e--) | |
| 1020 | + if(*e == c) | |
| 1021 | + return e; | |
| 1022 | + return nil; | |
| 1023 | +} | |
| 1024 | + | |
| 1025 | +/* | |
| 1026 | + * Turn a name into a channel. | |
| 1027 | + * &name[0] is known to be a valid address. It may be a kernel address. | |
| 1028 | + * | |
| 1029 | + * Opening with amode Aopen, Acreate, or Aremove guarantees | |
| 1030 | + * that the result will be the only reference to that particular fid. | |
| 1031 | + * This is necessary since we might pass the result to | |
| 1032 | + * devtab[]->remove(). | |
| 1033 | + * | |
| 1034 | + * Opening Atodir, Amount, or Aaccess does not guarantee this. | |
| 1035 | + * | |
| 1036 | + * Opening Aaccess can, under certain conditions, return a | |
| 1037 | + * correct Chan* but with an incorrect Cname attached. | |
| 1038 | + * Since the functions that open Aaccess (sysstat, syswstat, sys_stat) | |
| 1039 | + * do not use the Cname*, this avoids an unnecessary clone. | |
| 1040 | + */ | |
| 1041 | +Chan* | |
| 1042 | +namec(char *aname, int amode, int omode, ulong perm) | |
| 1043 | +{ | |
| 1044 | + int n, prefix, len, t, nomount, npath; | |
| 1045 | + Chan *c, *cnew; | |
| 1046 | + Cname *cname; | |
| 1047 | + Elemlist e; | |
| 1048 | + Rune r; | |
| 1049 | + Mhead *m; | |
| 1050 | + char *createerr, tmperrbuf[ERRMAX]; | |
| 1051 | + char *name; | |
| 1052 | + | |
| 1053 | + name = aname; | |
| 1054 | + if(name[0] == '\0') | |
| 1055 | + error("empty file name"); | |
| 1056 | + validname(name, 1); | |
| 1057 | + | |
| 1058 | + /* | |
| 1059 | + * Find the starting off point (the current slash, the root of | |
| 1060 | + * a device tree, or the current dot) as well as the name to | |
| 1061 | + * evaluate starting there. | |
| 1062 | + */ | |
| 1063 | + nomount = 0; | |
| 1064 | + switch(name[0]){ | |
| 1065 | + case '/': | |
| 1066 | + c = up->slash; | |
| 1067 | + incref(&c->ref); | |
| 1068 | + break; | |
| 1069 | + | |
| 1070 | + case '#': | |
| 1071 | + nomount = 1; | |
| 1072 | + up->genbuf[0] = '\0'; | |
| 1073 | + n = 0; | |
| 1074 | + while(*name!='\0' && (*name != '/' || n < 2)){ | |
| 1075 | + if(n >= sizeof(up->genbuf)-1) | |
| 1076 | + error(Efilename); | |
| 1077 | + up->genbuf[n++] = *name++; | |
| 1078 | + } | |
| 1079 | + up->genbuf[n] = '\0'; | |
| 1080 | + /* | |
| 1081 | + * noattach is sandboxing. | |
| 1082 | + * | |
| 1083 | + * the OK exceptions are: | |
| 1084 | + * | it only gives access to pipes you create | |
| 1085 | + * d this process's file descriptors | |
| 1086 | + * e this process's environment | |
| 1087 | + * the iffy exceptions are: | |
| 1088 | + * c time and pid, but also cons and consctl | |
| 1089 | + * p control of your own processes (and unfortunately | |
| 1090 | + * any others left unprotected) | |
| 1091 | + */ | |
| 1092 | + n = chartorune(&r, up->genbuf+1)+1; | |
| 1093 | + /* actually / is caught by parsing earlier */ | |
| 1094 | + if(utfrune("M", r)) | |
| 1095 | + error(Enoattach); | |
| 1096 | + if(up->pgrp->noattach && utfrune("|decp", r)==nil) | |
| 1097 | + error(Enoattach); | |
| 1098 | + t = devno(r, 1); | |
| 1099 | + if(t == -1) | |
| 1100 | + error(Ebadsharp); | |
| 1101 | + c = devtab[t]->attach(up->genbuf+n); | |
| 1102 | + break; | |
| 1103 | + | |
| 1104 | + default: | |
| 1105 | + c = up->dot; | |
| 1106 | + incref(&c->ref); | |
| 1107 | + break; | |
| 1108 | + } | |
| 1109 | + prefix = name - aname; | |
| 1110 | + | |
| 1111 | + e.name = nil; | |
| 1112 | + e.elems = nil; | |
| 1113 | + e.off = nil; | |
| 1114 | + e.nelems = 0; | |
| 1115 | + if(waserror()){ | |
| 1116 | + cclose(c); | |
| 1117 | + free(e.name); | |
| 1118 | + free(e.elems); | |
| 1119 | + free(e.off); | |
| 1120 | +//dumpmount(); | |
| 1121 | + nexterror(); | |
| 1122 | + } | |
| 1123 | + | |
| 1124 | + /* | |
| 1125 | + * Build a list of elements in the path. | |
| 1126 | + */ | |
| 1127 | + parsename(name, &e); | |
| 1128 | + | |
| 1129 | + /* | |
| 1130 | + * On create, .... | |
| 1131 | + */ | |
| 1132 | + if(amode == Acreate){ | |
| 1133 | + /* perm must have DMDIR if last element is / or /. */ | |
| 1134 | + if(e.mustbedir && !(perm&DMDIR)){ | |
| 1135 | + npath = e.nelems; | |
| 1136 | + strcpy(tmperrbuf, "create without DMDIR"); | |
| 1137 | + goto NameError; | |
| 1138 | + } | |
| 1139 | + | |
| 1140 | + /* don't try to walk the last path element just yet. */ | |
| 1141 | + if(e.nelems == 0) | |
| 1142 | + error(Eexist); | |
| 1143 | + e.nelems--; | |
| 1144 | + } | |
| 1145 | + | |
| 1146 | + if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){ | |
| 1147 | + if(npath < 0 || npath > e.nelems){ | |
| 1148 | + print("namec %s walk error npath=%d\n", aname, npath); | |
| 1149 | + nexterror(); | |
| 1150 | + } | |
| 1151 | + strcpy(tmperrbuf, up->errstr); | |
| 1152 | + NameError: | |
| 1153 | + len = prefix+e.off[npath]; | |
| 1154 | + if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname) | |
| 1155 | + snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname); | |
| 1156 | + else | |
| 1157 | + snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name); | |
| 1158 | + snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf); | |
| 1159 | + nexterror(); | |
| 1160 | + } | |
| 1161 | + | |
| 1162 | + if(e.mustbedir && !(c->qid.type&QTDIR)){ | |
| 1163 | + npath = e.nelems; | |
| 1164 | + strcpy(tmperrbuf, "not a directory"); | |
| 1165 | + goto NameError; | |
| 1166 | + } | |
| 1167 | + | |
| 1168 | + if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){ | |
| 1169 | + npath = e.nelems; | |
| 1170 | + error("cannot exec directory"); | |
| 1171 | + } | |
| 1172 | + | |
| 1173 | + switch(amode){ | |
| 1174 | + case Aaccess: | |
| 1175 | + if(!nomount) | |
| 1176 | + domount(&c, nil); | |
| 1177 | + break; | |
| 1178 | + | |
| 1179 | + case Abind: | |
| 1180 | + m = nil; | |
| 1181 | + if(!nomount) | |
| 1182 | + domount(&c, &m); | |
| 1183 | + if(c->umh != nil) | |
| 1184 | + putmhead(c->umh); | |
| 1185 | + c->umh = m; | |
| 1186 | + break; | |
| 1187 | + | |
| 1188 | + case Aremove: | |
| 1189 | + case Aopen: | |
| 1190 | + Open: | |
| 1191 | + /* save the name; domount might change c */ | |
| 1192 | + cname = c->name; | |
| 1193 | + incref(&cname->ref); | |
| 1194 | + m = nil; | |
| 1195 | + if(!nomount) | |
| 1196 | + domount(&c, &m); | |
| 1197 | + | |
| 1198 | + /* our own copy to open or remove */ | |
| 1199 | + c = cunique(c); | |
| 1200 | + | |
| 1201 | + /* now it's our copy anyway, we can put the name back */ | |
| 1202 | + cnameclose(c->name); | |
| 1203 | + c->name = cname; | |
| 1204 | + | |
| 1205 | + switch(amode){ | |
| 1206 | + case Aremove: | |
| 1207 | + putmhead(m); | |
| 1208 | + break; | |
| 1209 | + | |
| 1210 | + case Aopen: | |
| 1211 | + case Acreate: | |
| 1212 | +if(c->umh != nil){ | |
| 1213 | + print("cunique umh Open\n"); | |
| 1214 | + putmhead(c->umh); | |
| 1215 | + c->umh = nil; | |
| 1216 | +} | |
| 1217 | + | |
| 1218 | + /* only save the mount head if it's a multiple element union */ | |
| 1219 | + if(m && m->mount && m->mount->next) | |
| 1220 | + c->umh = m; | |
| 1221 | + else | |
| 1222 | + putmhead(m); | |
| 1223 | + | |
| 1224 | + /* save registers else error() in open has wrong value of c saved */ | |
| 1225 | + saveregisters(); | |
| 1226 | + | |
| 1227 | + if(omode == OEXEC) | |
| 1228 | + c->flag &= ~CCACHE; | |
| 1229 | + | |
| 1230 | + c = devtab[c->type]->open(c, omode&~OCEXEC); | |
| 1231 | + | |
| 1232 | + if(omode & OCEXEC) | |
| 1233 | + c->flag |= CCEXEC; | |
| 1234 | + if(omode & ORCLOSE) | |
| 1235 | + c->flag |= CRCLOSE; | |
| 1236 | + break; | |
| 1237 | + } | |
| 1238 | + break; | |
| 1239 | + | |
| 1240 | + case Atodir: | |
| 1241 | + /* | |
| 1242 | + * Directories (e.g. for cd) are left before the mount point, | |
| 1243 | + * so one may mount on / or . and see the effect. | |
| 1244 | + */ | |
| 1245 | + if(!(c->qid.type & QTDIR)) | |
| 1246 | + error(Enotdir); | |
| 1247 | + break; | |
| 1248 | + | |
| 1249 | + case Amount: | |
| 1250 | + /* | |
| 1251 | + * When mounting on an already mounted upon directory, | |
| 1252 | + * one wants subsequent mounts to be attached to the | |
| 1253 | + * original directory, not the replacement. Don't domount. | |
| 1254 | + */ | |
| 1255 | + break; | |
| 1256 | + | |
| 1257 | + case Acreate: | |
| 1258 | + /* | |
| 1259 | + * We've already walked all but the last element. | |
| 1260 | + * If the last exists, try to open it OTRUNC. | |
| 1261 | + * If omode&OEXCL is set, just give up. | |
| 1262 | + */ | |
| 1263 | + e.nelems++; | |
| 1264 | + if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){ | |
| 1265 | + if(omode&OEXCL) | |
| 1266 | + error(Eexist); | |
| 1267 | + omode |= OTRUNC; | |
| 1268 | + goto Open; | |
| 1269 | + } | |
| 1270 | + | |
| 1271 | + /* | |
| 1272 | + * The semantics of the create(2) system call are that if the | |
| 1273 | + * file exists and can be written, it is to be opened with truncation. | |
| 1274 | + * On the other hand, the create(5) message fails if the file exists. | |
| 1275 | + * If we get two create(2) calls happening simultaneously, | |
| 1276 | + * they might both get here and send create(5) messages, but only | |
| 1277 | + * one of the messages will succeed. To provide the expected create(2) | |
| 1278 | + * semantics, the call with the failed message needs to try the above | |
| 1279 | + * walk again, opening for truncation. This correctly solves the | |
| 1280 | + * create/create race, in the sense that any observable outcome can | |
| 1281 | + * be explained as one happening before the other. | |
| 1282 | + * The create/create race is quite common. For example, it happens | |
| 1283 | + * when two rc subshells simultaneously update the same | |
| 1284 | + * environment variable. | |
| 1285 | + * | |
| 1286 | + * The implementation still admits a create/create/remove race: | |
| 1287 | + * (A) walk to file, fails | |
| 1288 | + * (B) walk to file, fails | |
| 1289 | + * (A) create file, succeeds, returns | |
| 1290 | + * (B) create file, fails | |
| 1291 | + * (A) remove file, succeeds, returns | |
| 1292 | + * (B) walk to file, return failure. | |
| 1293 | + * | |
| 1294 | + * This is hardly as common as the create/create race, and is really | |
| 1295 | + * not too much worse than what might happen if (B) got a hold of a | |
| 1296 | + * file descriptor and then the file was removed -- either way (B) can't do | |
| 1297 | + * anything with the result of the create call. So we don't care about this race. | |
| 1298 | + * | |
| 1299 | + * Applications that care about more fine-grained decision of the races | |
| 1300 | + * can use the OEXCL flag to get at the underlying create(5) semantics; | |
| 1301 | + * by default we provide the common case. | |
| 1302 | + * | |
| 1303 | + * We need to stay behind the mount point in case we | |
| 1304 | + * need to do the first walk again (should the create fail). | |
| 1305 | + * | |
| 1306 | + * We also need to cross the mount point and find the directory | |
| 1307 | + * in the union in which we should be creating. | |
| 1308 | + * | |
| 1309 | + * The channel staying behind is c, the one moving forward is cnew. | |
| 1310 | + */ | |
| 1311 | + m = nil; | |
| 1312 | + cnew = nil; /* is this assignment necessary? */ | |
| 1313 | + if(!waserror()){ /* try create */ | |
| 1314 | + if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid)) | |
| 1315 | + cnew = createdir(cnew, m); | |
| 1316 | + else{ | |
| 1317 | + cnew = c; | |
| 1318 | + incref(&cnew->ref); | |
| 1319 | + } | |
| 1320 | + | |
| 1321 | + /* | |
| 1322 | + * We need our own copy of the Chan because we're | |
| 1323 | + * about to send a create, which will move it. Once we have | |
| 1324 | + * our own copy, we can fix the name, which might be wrong | |
| 1325 | + * if findmount gave us a new Chan. | |
| 1326 | + */ | |
| 1327 | + cnew = cunique(cnew); | |
| 1328 | + cnameclose(cnew->name); | |
| 1329 | + cnew->name = c->name; | |
| 1330 | + incref(&cnew->name->ref); | |
| 1331 | + | |
| 1332 | + devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm); | |
| 1333 | + poperror(); | |
| 1334 | + if(omode & OCEXEC) | |
| 1335 | + cnew->flag |= CCEXEC; | |
| 1336 | + if(omode & ORCLOSE) | |
| 1337 | + cnew->flag |= CRCLOSE; | |
| 1338 | + if(m) | |
| 1339 | + putmhead(m); | |
| 1340 | + cclose(c); | |
| 1341 | + c = cnew; | |
| 1342 | + c->name = addelem(c->name, e.elems[e.nelems-1]); | |
| 1343 | + break; | |
| 1344 | + }else{ /* create failed */ | |
| 1345 | + cclose(cnew); | |
| 1346 | + if(m) | |
| 1347 | + putmhead(m); | |
| 1348 | + if(omode & OEXCL) | |
| 1349 | + nexterror(); | |
| 1350 | + /* save error */ | |
| 1351 | + createerr = up->errstr; | |
| 1352 | + up->errstr = tmperrbuf; | |
| 1353 | + /* note: we depend that walk does not error */ | |
| 1354 | + if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){ | |
| 1355 | + up->errstr = createerr; | |
| 1356 | + error(createerr); /* report true error */ | |
| 1357 | + } | |
| 1358 | + up->errstr = createerr; | |
| 1359 | + omode |= OTRUNC; | |
| 1360 | + goto Open; | |
| 1361 | + } | |
| 1362 | + panic("namec: not reached"); | |
| 1363 | + | |
| 1364 | + default: | |
| 1365 | + panic("unknown namec access %d\n", amode); | |
| 1366 | + } | |
| 1367 | + | |
| 1368 | + poperror(); | |
| 1369 | + | |
| 1370 | + /* place final element in genbuf for e.g. exec */ | |
| 1371 | + if(e.nelems > 0) | |
| 1372 | + kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf); | |
| 1373 | + else | |
| 1374 | + kstrcpy(up->genbuf, ".", sizeof up->genbuf); | |
| 1375 | + free(e.name); | |
| 1376 | + free(e.elems); | |
| 1377 | + free(e.off); | |
| 1378 | + | |
| 1379 | + return c; | |
| 1380 | +} | |
| 1381 | + | |
| 1382 | +/* | |
| 1383 | + * name is valid. skip leading / and ./ as much as possible | |
| 1384 | + */ | |
| 1385 | +char* | |
| 1386 | +skipslash(char *name) | |
| 1387 | +{ | |
| 1388 | + while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/'))) | |
| 1389 | + name++; | |
| 1390 | + return name; | |
| 1391 | +} | |
| 1392 | + | |
| 1393 | +char isfrog[256]={ | |
| 1394 | + /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */ | |
| 1395 | + /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */ | |
| 1396 | + /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */ | |
| 1397 | + /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */ | |
| 1398 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ | |
| 1399 | + 0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */ | |
| 1400 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ | |
| 1401 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ | |
| 1402 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ | |
| 1403 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */ | |
| 1404 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ | |
| 1405 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ | |
| 1406 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ | |
| 1407 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */ | |
| 1408 | + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ | |
| 1409 | + 0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */ | |
| 1410 | +}; | |
| 1411 | + | |
| 1412 | +/* | |
| 1413 | + * Check that the name | |
| 1414 | + * a) is in valid memory. | |
| 1415 | + * b) is shorter than 2^16 bytes, so it can fit in a 9P string field. | |
| 1416 | + * c) contains no frogs. | |
| 1417 | + * The first byte is known to be addressible by the requester, so the | |
| 1418 | + * routine works for kernel and user memory both. | |
| 1419 | + * The parameter slashok flags whether a slash character is an error | |
| 1420 | + * or a valid character. | |
| 1421 | + */ | |
| 1422 | +void | |
| 1423 | +validname(char *aname, int slashok) | |
| 1424 | +{ | |
| 1425 | + char *p, *ename, *name; | |
| 1426 | + uint t; | |
| 1427 | + int c; | |
| 1428 | + Rune r; | |
| 1429 | + | |
| 1430 | + name = aname; | |
| 1431 | +/* | |
| 1432 | + if(((ulong)name & KZERO) != KZERO) { | |
| 1433 | + p = name; | |
| 1434 | + t = BY2PG-((ulong)p&(BY2PG-1)); | |
| 1435 | + while((ename=vmemchr(p, 0, t)) == nil) { | |
| 1436 | + p += t; | |
| 1437 | + t = BY2PG; | |
| 1438 | + } | |
| 1439 | + }else | |
| 1440 | +*/ | |
| 1441 | + ename = memchr(name, 0, (1<<16)); | |
| 1442 | + | |
| 1443 | + if(ename==nil || ename-name>=(1<<16)) | |
| 1444 | + error("name too long"); | |
| 1445 | + | |
| 1446 | + while(*name){ | |
| 1447 | + /* all characters above '~' are ok */ | |
| 1448 | + c = *(uchar*)name; | |
| 1449 | + if(c >= Runeself) | |
| 1450 | + name += chartorune(&r, name); | |
| 1451 | + else{ | |
| 1452 | + if(isfrog[c]) | |
| 1453 | + if(!slashok || c!='/'){ | |
| 1454 | + snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname); | |
| 1455 | + error(up->genbuf); | |
| 1456 | + } | |
| 1457 | + name++; | |
| 1458 | + } | |
| 1459 | + } | |
| 1460 | +} | |
| 1461 | + | |
| 1462 | +void | |
| 1463 | +isdir(Chan *c) | |
| 1464 | +{ | |
| 1465 | + if(c->qid.type & QTDIR) | |
| 1466 | + return; | |
| 1467 | + error(Enotdir); | |
| 1468 | +} | |
| 1469 | + | |
| 1470 | +/* | |
| 1471 | + * This is necessary because there are many | |
| 1472 | + * pointers to the top of a given mount list: | |
| 1473 | + * | |
| 1474 | + * - the mhead in the namespace hash table | |
| 1475 | + * - the mhead in chans returned from findmount: | |
| 1476 | + * used in namec and then by unionread. | |
| 1477 | + * - the mhead in chans returned from createdir: | |
| 1478 | + * used in the open/create race protect, which is gone. | |
| 1479 | + * | |
| 1480 | + * The RWlock in the Mhead protects the mount list it contains. | |
| 1481 | + * The mount list is deleted when we cunmount. | |
| 1482 | + * The RWlock ensures that nothing is using the mount list at that time. | |
| 1483 | + * | |
| 1484 | + * It is okay to replace c->mh with whatever you want as | |
| 1485 | + * long as you are sure you have a unique reference to it. | |
| 1486 | + * | |
| 1487 | + * This comment might belong somewhere else. | |
| 1488 | + */ | |
| 1489 | +void | |
| 1490 | +putmhead(Mhead *m) | |
| 1491 | +{ | |
| 1492 | + if(m && decref(&m->ref) == 0){ | |
| 1493 | + m->mount = (Mount*)0xCafeBeef; | |
| 1494 | + free(m); | |
| 1495 | + } | |
| 1496 | +} | |
| @@ -0,0 +1,519 @@ | ||
| 1 | +#define KNAMELEN 28 /* max length of name held in kernel */ | |
| 2 | +#define DOMLEN 64 | |
| 3 | + | |
| 4 | +#define BLOCKALIGN 8 | |
| 5 | + | |
| 6 | +typedef struct Alarms Alarms; | |
| 7 | +typedef struct Block Block; | |
| 8 | +typedef struct CSN CSN; | |
| 9 | +typedef struct Chan Chan; | |
| 10 | +typedef struct Cmdbuf Cmdbuf; | |
| 11 | +typedef struct Cmdtab Cmdtab; | |
| 12 | +typedef struct Cname Cname; | |
| 13 | +typedef struct Conf Conf; | |
| 14 | +typedef struct Dev Dev; | |
| 15 | +typedef struct Dirtab Dirtab; | |
| 16 | +typedef struct Edfinterface Edfinterface; | |
| 17 | +typedef struct Egrp Egrp; | |
| 18 | +typedef struct Evalue Evalue; | |
| 19 | +typedef struct Fgrp Fgrp; | |
| 20 | +typedef struct FPsave FPsave; | |
| 21 | +typedef struct DevConf DevConf; | |
| 22 | +typedef struct Label Label; | |
| 23 | +typedef struct List List; | |
| 24 | +typedef struct Log Log; | |
| 25 | +typedef struct Logflag Logflag; | |
| 26 | +typedef struct Mntcache Mntcache; | |
| 27 | +typedef struct Mount Mount; | |
| 28 | +typedef struct Mntrpc Mntrpc; | |
| 29 | +typedef struct Mntwalk Mntwalk; | |
| 30 | +typedef struct Mnt Mnt; | |
| 31 | +typedef struct Mhead Mhead; | |
| 32 | +typedef struct Note Note; | |
| 33 | +typedef struct Page Page; | |
| 34 | +typedef struct Palloc Palloc; | |
| 35 | +typedef struct Perf Perf; | |
| 36 | +typedef struct Pgrps Pgrps; | |
| 37 | +typedef struct PhysUart PhysUart; | |
| 38 | +typedef struct Pgrp Pgrp; | |
| 39 | +typedef struct Physseg Physseg; | |
| 40 | +typedef struct Proc Proc; | |
| 41 | +typedef struct Pte Pte; | |
| 42 | +typedef struct Pthash Pthash; | |
| 43 | +typedef struct Queue Queue; | |
| 44 | +typedef struct Ref Ref; | |
| 45 | +typedef struct Rendez Rendez; | |
| 46 | +typedef struct Rgrp Rgrp; | |
| 47 | +typedef struct RWlock RWlock; | |
| 48 | +typedef struct Schedq Schedq; | |
| 49 | +typedef struct Segment Segment; | |
| 50 | +typedef struct Session Session; | |
| 51 | +typedef struct Task Task; | |
| 52 | +typedef struct Talarm Talarm; | |
| 53 | +typedef struct Timer Timer; | |
| 54 | +typedef struct Uart Uart; | |
| 55 | +typedef struct Ureg Ureg; | |
| 56 | +typedef struct Waitq Waitq; | |
| 57 | +typedef struct Walkqid Walkqid; | |
| 58 | +typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*); | |
| 59 | + | |
| 60 | +#include "fcall.h" | |
| 61 | + | |
| 62 | +enum | |
| 63 | +{ | |
| 64 | + SnarfSize = 64*1024, | |
| 65 | +}; | |
| 66 | + | |
| 67 | +struct Conf | |
| 68 | +{ | |
| 69 | + ulong nmach; /* processors */ | |
| 70 | + ulong nproc; /* processes */ | |
| 71 | + ulong monitor; /* has monitor? */ | |
| 72 | + ulong npage0; /* total physical pages of memory */ | |
| 73 | + ulong npage1; /* total physical pages of memory */ | |
| 74 | + ulong npage; /* total physical pages of memory */ | |
| 75 | + ulong upages; /* user page pool */ | |
| 76 | + ulong nimage; /* number of page cache image headers */ | |
| 77 | + ulong nswap; /* number of swap pages */ | |
| 78 | + int nswppo; /* max # of pageouts per segment pass */ | |
| 79 | + ulong base0; /* base of bank 0 */ | |
| 80 | + ulong base1; /* base of bank 1 */ | |
| 81 | + ulong copymode; /* 0 is copy on write, 1 is copy on reference */ | |
| 82 | + ulong ialloc; /* max interrupt time allocation in bytes */ | |
| 83 | + ulong pipeqsize; /* size in bytes of pipe queues */ | |
| 84 | + int nuart; /* number of uart devices */ | |
| 85 | +}; | |
| 86 | + | |
| 87 | +struct Label | |
| 88 | +{ | |
| 89 | + jmp_buf buf; | |
| 90 | +}; | |
| 91 | + | |
| 92 | +struct Ref | |
| 93 | +{ | |
| 94 | + Lock lk; | |
| 95 | + long ref; | |
| 96 | +}; | |
| 97 | + | |
| 98 | +struct Rendez | |
| 99 | +{ | |
| 100 | + Lock lk; | |
| 101 | + Proc *p; | |
| 102 | +}; | |
| 103 | + | |
| 104 | +struct RWlock /* changed from kernel */ | |
| 105 | +{ | |
| 106 | + int readers; | |
| 107 | + Lock lk; | |
| 108 | + QLock x; | |
| 109 | + QLock k; | |
| 110 | +}; | |
| 111 | + | |
| 112 | +struct Talarm | |
| 113 | +{ | |
| 114 | + Lock lk; | |
| 115 | + Proc *list; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +struct Alarms | |
| 119 | +{ | |
| 120 | + QLock lk; | |
| 121 | + Proc *head; | |
| 122 | +}; | |
| 123 | + | |
| 124 | +/* | |
| 125 | + * Access types in namec & channel flags | |
| 126 | + */ | |
| 127 | +enum | |
| 128 | +{ | |
| 129 | + Aaccess, /* as in stat, wstat */ | |
| 130 | + Abind, /* for left-hand-side of bind */ | |
| 131 | + Atodir, /* as in chdir */ | |
| 132 | + Aopen, /* for i/o */ | |
| 133 | + Amount, /* to be mounted or mounted upon */ | |
| 134 | + Acreate, /* is to be created */ | |
| 135 | + Aremove, /* will be removed by caller */ | |
| 136 | + | |
| 137 | + COPEN = 0x0001, /* for i/o */ | |
| 138 | + CMSG = 0x0002, /* the message channel for a mount */ | |
| 139 | +/*rsc CCREATE = 0x0004, /* permits creation if c->mnt */ | |
| 140 | + CCEXEC = 0x0008, /* close on exec */ | |
| 141 | + CFREE = 0x0010, /* not in use */ | |
| 142 | + CRCLOSE = 0x0020, /* remove on close */ | |
| 143 | + CCACHE = 0x0080, /* client cache */ | |
| 144 | +}; | |
| 145 | + | |
| 146 | +/* flag values */ | |
| 147 | +enum | |
| 148 | +{ | |
| 149 | + BINTR = (1<<0), | |
| 150 | + BFREE = (1<<1), | |
| 151 | + Bipck = (1<<2), /* ip checksum */ | |
| 152 | + Budpck = (1<<3), /* udp checksum */ | |
| 153 | + Btcpck = (1<<4), /* tcp checksum */ | |
| 154 | + Bpktck = (1<<5), /* packet checksum */ | |
| 155 | +}; | |
| 156 | + | |
| 157 | +struct Block | |
| 158 | +{ | |
| 159 | + Block* next; | |
| 160 | + Block* list; | |
| 161 | + uchar* rp; /* first unconsumed byte */ | |
| 162 | + uchar* wp; /* first empty byte */ | |
| 163 | + uchar* lim; /* 1 past the end of the buffer */ | |
| 164 | + uchar* base; /* start of the buffer */ | |
| 165 | + void (*free)(Block*); | |
| 166 | + ushort flag; | |
| 167 | + ushort checksum; /* IP checksum of complete packet (minus media header) */ | |
| 168 | +}; | |
| 169 | +#define BLEN(s) ((s)->wp - (s)->rp) | |
| 170 | +#define BALLOC(s) ((s)->lim - (s)->base) | |
| 171 | + | |
| 172 | +struct Chan | |
| 173 | +{ | |
| 174 | + Ref ref; | |
| 175 | + Chan* next; /* allocation */ | |
| 176 | + Chan* link; | |
| 177 | + vlong offset; /* in file */ | |
| 178 | + ushort type; | |
| 179 | + ulong dev; | |
| 180 | + ushort mode; /* read/write */ | |
| 181 | + ushort flag; | |
| 182 | + Qid qid; | |
| 183 | + int fid; /* for devmnt */ | |
| 184 | + ulong iounit; /* chunk size for i/o; 0==default */ | |
| 185 | + Mhead* umh; /* mount point that derived Chan; used in unionread */ | |
| 186 | + Chan* umc; /* channel in union; held for union read */ | |
| 187 | + QLock umqlock; /* serialize unionreads */ | |
| 188 | + int uri; /* union read index */ | |
| 189 | + int dri; /* devdirread index */ | |
| 190 | + ulong mountid; | |
| 191 | + Mntcache *mcp; /* Mount cache pointer */ | |
| 192 | + Mnt *mux; /* Mnt for clients using me for messages */ | |
| 193 | + void* aux; | |
| 194 | + Qid pgrpid; /* for #p/notepg */ | |
| 195 | + ulong mid; /* for ns in devproc */ | |
| 196 | + Chan* mchan; /* channel to mounted server */ | |
| 197 | + Qid mqid; /* qid of root of mount point */ | |
| 198 | + Session*session; | |
| 199 | + Cname *name; | |
| 200 | +}; | |
| 201 | + | |
| 202 | +struct Cname | |
| 203 | +{ | |
| 204 | + Ref ref; | |
| 205 | + int alen; /* allocated length */ | |
| 206 | + int len; /* strlen(s) */ | |
| 207 | + char *s; | |
| 208 | +}; | |
| 209 | + | |
| 210 | +struct Dev | |
| 211 | +{ | |
| 212 | + int dc; | |
| 213 | + char* name; | |
| 214 | + | |
| 215 | + void (*reset)(void); | |
| 216 | + void (*init)(void); | |
| 217 | + void (*shutdown)(void); | |
| 218 | + Chan* (*attach)(char*); | |
| 219 | + Walkqid* (*walk)(Chan*, Chan*, char**, int); | |
| 220 | + int (*stat)(Chan*, uchar*, int); | |
| 221 | + Chan* (*open)(Chan*, int); | |
| 222 | + void (*create)(Chan*, char*, int, ulong); | |
| 223 | + void (*close)(Chan*); | |
| 224 | + long (*read)(Chan*, void*, long, vlong); | |
| 225 | + Block* (*bread)(Chan*, long, ulong); | |
| 226 | + long (*write)(Chan*, void*, long, vlong); | |
| 227 | + long (*bwrite)(Chan*, Block*, ulong); | |
| 228 | + void (*remove)(Chan*); | |
| 229 | + int (*wstat)(Chan*, uchar*, int); | |
| 230 | + void (*power)(int); /* power mgt: power(1) => on, power (0) => off */ | |
| 231 | + int (*config)(int, char*, DevConf*); // returns nil on error | |
| 232 | +}; | |
| 233 | + | |
| 234 | +struct Dirtab | |
| 235 | +{ | |
| 236 | + char name[KNAMELEN]; | |
| 237 | + Qid qid; | |
| 238 | + vlong length; | |
| 239 | + long perm; | |
| 240 | +}; | |
| 241 | + | |
| 242 | +struct Walkqid | |
| 243 | +{ | |
| 244 | + Chan *clone; | |
| 245 | + int nqid; | |
| 246 | + Qid qid[1]; | |
| 247 | +}; | |
| 248 | + | |
| 249 | +enum | |
| 250 | +{ | |
| 251 | + NSMAX = 1000, | |
| 252 | + NSLOG = 7, | |
| 253 | + NSCACHE = (1<<NSLOG), | |
| 254 | +}; | |
| 255 | + | |
| 256 | +struct Mntwalk /* state for /proc/#/ns */ | |
| 257 | +{ | |
| 258 | + int cddone; | |
| 259 | + ulong id; | |
| 260 | + Mhead* mh; | |
| 261 | + Mount* cm; | |
| 262 | +}; | |
| 263 | + | |
| 264 | +struct Mount | |
| 265 | +{ | |
| 266 | + ulong mountid; | |
| 267 | + Mount* next; | |
| 268 | + Mhead* head; | |
| 269 | + Mount* copy; | |
| 270 | + Mount* order; | |
| 271 | + Chan* to; /* channel replacing channel */ | |
| 272 | + int mflag; | |
| 273 | + char *spec; | |
| 274 | +}; | |
| 275 | + | |
| 276 | +struct Mhead | |
| 277 | +{ | |
| 278 | + Ref ref; | |
| 279 | + RWlock lock; | |
| 280 | + Chan* from; /* channel mounted upon */ | |
| 281 | + Mount* mount; /* what's mounted upon it */ | |
| 282 | + Mhead* hash; /* Hash chain */ | |
| 283 | +}; | |
| 284 | + | |
| 285 | +struct Mnt | |
| 286 | +{ | |
| 287 | + Lock lk; | |
| 288 | + /* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */ | |
| 289 | + Chan *c; /* Channel to file service */ | |
| 290 | + Proc *rip; /* Reader in progress */ | |
| 291 | + Mntrpc *queue; /* Queue of pending requests on this channel */ | |
| 292 | + ulong id; /* Multiplexer id for channel check */ | |
| 293 | + Mnt *list; /* Free list */ | |
| 294 | + int flags; /* cache */ | |
| 295 | + int msize; /* data + IOHDRSZ */ | |
| 296 | + char *version; /* 9P version */ | |
| 297 | + Queue *q; /* input queue */ | |
| 298 | +}; | |
| 299 | + | |
| 300 | +enum | |
| 301 | +{ | |
| 302 | + NUser, /* note provided externally */ | |
| 303 | + NExit, /* deliver note quietly */ | |
| 304 | + NDebug, /* print debug message */ | |
| 305 | +}; | |
| 306 | + | |
| 307 | +struct Note | |
| 308 | +{ | |
| 309 | + char msg[ERRMAX]; | |
| 310 | + int flag; /* whether system posted it */ | |
| 311 | +}; | |
| 312 | + | |
| 313 | +enum | |
| 314 | +{ | |
| 315 | + RENDLOG = 5, | |
| 316 | + RENDHASH = 1<<RENDLOG, /* Hash to lookup rendezvous tags */ | |
| 317 | + MNTLOG = 5, | |
| 318 | + MNTHASH = 1<<MNTLOG, /* Hash to walk mount table */ | |
| 319 | + NFD = 100, /* per process file descriptors */ | |
| 320 | + PGHLOG = 9, | |
| 321 | + PGHSIZE = 1<<PGHLOG, /* Page hash for image lookup */ | |
| 322 | +}; | |
| 323 | +#define REND(p,s) ((p)->rendhash[(s)&((1<<RENDLOG)-1)]) | |
| 324 | +#define MOUNTH(p,qid) ((p)->mnthash[(qid).path&((1<<MNTLOG)-1)]) | |
| 325 | + | |
| 326 | +struct Pgrp | |
| 327 | +{ | |
| 328 | + Ref ref; /* also used as a lock when mounting */ | |
| 329 | + int noattach; | |
| 330 | + ulong pgrpid; | |
| 331 | + QLock debug; /* single access via devproc.c */ | |
| 332 | + RWlock ns; /* Namespace n read/one write lock */ | |
| 333 | + Mhead *mnthash[MNTHASH]; | |
| 334 | +}; | |
| 335 | + | |
| 336 | +struct Rgrp | |
| 337 | +{ | |
| 338 | + Ref ref; | |
| 339 | + Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */ | |
| 340 | +}; | |
| 341 | + | |
| 342 | +struct Egrp | |
| 343 | +{ | |
| 344 | + Ref ref; | |
| 345 | + RWlock lk; | |
| 346 | + Evalue **ent; | |
| 347 | + int nent; | |
| 348 | + int ment; | |
| 349 | + ulong path; /* qid.path of next Evalue to be allocated */ | |
| 350 | + ulong vers; /* of Egrp */ | |
| 351 | +}; | |
| 352 | + | |
| 353 | +struct Evalue | |
| 354 | +{ | |
| 355 | + char *name; | |
| 356 | + char *value; | |
| 357 | + int len; | |
| 358 | + Evalue *link; | |
| 359 | + Qid qid; | |
| 360 | +}; | |
| 361 | + | |
| 362 | +struct Fgrp | |
| 363 | +{ | |
| 364 | + Ref ref; | |
| 365 | + Chan **fd; | |
| 366 | + int nfd; /* number allocated */ | |
| 367 | + int maxfd; /* highest fd in use */ | |
| 368 | + int exceed; /* debugging */ | |
| 369 | +}; | |
| 370 | + | |
| 371 | +enum | |
| 372 | +{ | |
| 373 | + DELTAFD = 20, /* incremental increase in Fgrp.fd's */ | |
| 374 | + NERR = 20 | |
| 375 | +}; | |
| 376 | + | |
| 377 | +typedef uvlong Ticks; | |
| 378 | + | |
| 379 | +enum | |
| 380 | +{ | |
| 381 | + Running, | |
| 382 | + Rendezvous, | |
| 383 | + Wakeme, | |
| 384 | +}; | |
| 385 | + | |
| 386 | +struct Proc | |
| 387 | +{ | |
| 388 | + uint state; | |
| 389 | + uint mach; | |
| 390 | + | |
| 391 | + ulong pid; | |
| 392 | + ulong parentpid; | |
| 393 | + | |
| 394 | + Pgrp *pgrp; /* Process group for namespace */ | |
| 395 | + Fgrp *fgrp; /* File descriptor group */ | |
| 396 | + Rgrp *rgrp; | |
| 397 | + | |
| 398 | + Lock rlock; /* sync sleep/wakeup with postnote */ | |
| 399 | + Rendez *r; /* rendezvous point slept on */ | |
| 400 | + Rendez sleep; /* place for syssleep/debug */ | |
| 401 | + int notepending; /* note issued but not acted on */ | |
| 402 | + int kp; /* true if a kernel process */ | |
| 403 | + | |
| 404 | + ulong rendtag; /* Tag for rendezvous */ | |
| 405 | + ulong rendval; /* Value for rendezvous */ | |
| 406 | + Proc *rendhash; /* Hash list for tag values */ | |
| 407 | + | |
| 408 | + int nerrlab; | |
| 409 | + Label errlab[NERR]; | |
| 410 | + char user[KNAMELEN]; | |
| 411 | + char *syserrstr; /* last error from a system call, errbuf0 or 1 */ | |
| 412 | + char *errstr; /* reason we're unwinding the error stack, errbuf1 or 0 */ | |
| 413 | + char errbuf0[ERRMAX]; | |
| 414 | + char errbuf1[ERRMAX]; | |
| 415 | + char genbuf[128]; /* buffer used e.g. for last name element from namec */ | |
| 416 | + char text[KNAMELEN]; | |
| 417 | + | |
| 418 | + Chan *slash; | |
| 419 | + Chan *dot; | |
| 420 | + | |
| 421 | + Proc *qnext; | |
| 422 | + | |
| 423 | + void (*fn)(void*); | |
| 424 | + void *arg; | |
| 425 | + | |
| 426 | + char oproc[1024]; /* reserved for os */ | |
| 427 | + | |
| 428 | +}; | |
| 429 | + | |
| 430 | +enum | |
| 431 | +{ | |
| 432 | + PRINTSIZE = 256, | |
| 433 | + MAXCRYPT = 127, | |
| 434 | + NUMSIZE = 12, /* size of formatted number */ | |
| 435 | + MB = (1024*1024), | |
| 436 | + READSTR = 1000, /* temporary buffer size for device reads */ | |
| 437 | +}; | |
| 438 | + | |
| 439 | +extern char* conffile; | |
| 440 | +extern int cpuserver; | |
| 441 | +extern Dev* devtab[]; | |
| 442 | +extern char *eve; | |
| 443 | +extern char hostdomain[]; | |
| 444 | +extern uchar initcode[]; | |
| 445 | +extern Queue* kbdq; | |
| 446 | +extern Queue* kprintoq; | |
| 447 | +extern Ref noteidalloc; | |
| 448 | +extern Palloc palloc; | |
| 449 | +extern Queue *serialoq; | |
| 450 | +extern char* statename[]; | |
| 451 | +extern int nsyscall; | |
| 452 | +extern char *sysname; | |
| 453 | +extern uint qiomaxatomic; | |
| 454 | +extern Conf conf; | |
| 455 | +enum | |
| 456 | +{ | |
| 457 | + LRESPROF = 3, | |
| 458 | +}; | |
| 459 | + | |
| 460 | +/* | |
| 461 | + * action log | |
| 462 | + */ | |
| 463 | +struct Log { | |
| 464 | + Lock lk; | |
| 465 | + int opens; | |
| 466 | + char* buf; | |
| 467 | + char *end; | |
| 468 | + char *rptr; | |
| 469 | + int len; | |
| 470 | + int nlog; | |
| 471 | + int minread; | |
| 472 | + | |
| 473 | + int logmask; /* mask of things to debug */ | |
| 474 | + | |
| 475 | + QLock readq; | |
| 476 | + Rendez readr; | |
| 477 | +}; | |
| 478 | + | |
| 479 | +struct Logflag { | |
| 480 | + char* name; | |
| 481 | + int mask; | |
| 482 | +}; | |
| 483 | + | |
| 484 | +enum | |
| 485 | +{ | |
| 486 | + NCMDFIELD = 128 | |
| 487 | +}; | |
| 488 | + | |
| 489 | +struct Cmdbuf | |
| 490 | +{ | |
| 491 | + char *buf; | |
| 492 | + char **f; | |
| 493 | + int nf; | |
| 494 | +}; | |
| 495 | + | |
| 496 | +struct Cmdtab | |
| 497 | +{ | |
| 498 | + int index; /* used by client to switch on result */ | |
| 499 | + char *cmd; /* command name */ | |
| 500 | + int narg; /* expected #args; 0 ==> variadic */ | |
| 501 | +}; | |
| 502 | + | |
| 503 | +/* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */ | |
| 504 | +enum | |
| 505 | +{ | |
| 506 | + /* Queue.state */ | |
| 507 | + Qstarve = (1<<0), /* consumer starved */ | |
| 508 | + Qmsg = (1<<1), /* message stream */ | |
| 509 | + Qclosed = (1<<2), /* queue has been closed/hungup */ | |
| 510 | + Qflow = (1<<3), /* producer flow controlled */ | |
| 511 | + Qcoalesce = (1<<4), /* coallesce packets on read */ | |
| 512 | + Qkick = (1<<5), /* always call the kick routine after qwrite */ | |
| 513 | +}; | |
| 514 | + | |
| 515 | +#define DEVDOTDOT -1 | |
| 516 | + | |
| 517 | +extern Proc *_getproc(void); | |
| 518 | +extern void _setproc(Proc*); | |
| 519 | +#define up (_getproc()) | |
| @@ -0,0 +1,31 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +Proc *up; | |
| 8 | +Conf conf = | |
| 9 | +{ | |
| 10 | + 1, | |
| 11 | + 100, | |
| 12 | + 0, | |
| 13 | + 1024*1024*1024, | |
| 14 | + 1024*1024*1024, | |
| 15 | + 1024*1024*1024, | |
| 16 | + 1024*1024*1024, | |
| 17 | + 1024*1024*1024, | |
| 18 | + 1024*1024*1024, | |
| 19 | + 1024*1024*1024, | |
| 20 | + 1024*1024*1024, | |
| 21 | + 1024*1024*1024, | |
| 22 | + 1024*1024*1024, | |
| 23 | + 1024*1024*1024, | |
| 24 | + 1024*1024*1024, | |
| 25 | + 0, | |
| 26 | +}; | |
| 27 | + | |
| 28 | +char *eve = "eve"; | |
| 29 | +ulong kerndate; | |
| 30 | +int cpuserver; | |
| 31 | +char hostdomain[] = "drawterm.net"; | |
| @@ -0,0 +1,468 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +extern ulong kerndate; | |
| 8 | + | |
| 9 | +void | |
| 10 | +mkqid(Qid *q, vlong path, ulong vers, int type) | |
| 11 | +{ | |
| 12 | + q->type = type; | |
| 13 | + q->vers = vers; | |
| 14 | + q->path = path; | |
| 15 | +} | |
| 16 | + | |
| 17 | +int | |
| 18 | +devno(int c, int user) | |
| 19 | +{ | |
| 20 | + int i; | |
| 21 | + | |
| 22 | + for(i = 0; devtab[i] != nil; i++) { | |
| 23 | + if(devtab[i]->dc == c) | |
| 24 | + return i; | |
| 25 | + } | |
| 26 | + if(user == 0) | |
| 27 | + panic("devno %C 0x%ux", c, c); | |
| 28 | + | |
| 29 | + return -1; | |
| 30 | +} | |
| 31 | + | |
| 32 | +void | |
| 33 | +devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db) | |
| 34 | +{ | |
| 35 | + db->name = n; | |
| 36 | + if(c->flag&CMSG) | |
| 37 | + qid.type |= QTMOUNT; | |
| 38 | + db->qid = qid; | |
| 39 | + db->type = devtab[c->type]->dc; | |
| 40 | + db->dev = c->dev; | |
| 41 | + db->mode = perm; | |
| 42 | + db->mode |= qid.type << 24; | |
| 43 | + db->atime = seconds(); | |
| 44 | + db->mtime = kerndate; | |
| 45 | + db->length = length; | |
| 46 | + db->uid = user; | |
| 47 | + db->gid = eve; | |
| 48 | + db->muid = user; | |
| 49 | +} | |
| 50 | + | |
| 51 | +/* | |
| 52 | + * (here, Devgen is the prototype; devgen is the function in dev.c.) | |
| 53 | + * | |
| 54 | + * a Devgen is expected to return the directory entry for ".." | |
| 55 | + * if you pass it s==DEVDOTDOT (-1). otherwise... | |
| 56 | + * | |
| 57 | + * there are two contradictory rules. | |
| 58 | + * | |
| 59 | + * (i) if c is a directory, a Devgen is expected to list its children | |
| 60 | + * as you iterate s. | |
| 61 | + * | |
| 62 | + * (ii) whether or not c is a directory, a Devgen is expected to list | |
| 63 | + * its siblings as you iterate s. | |
| 64 | + * | |
| 65 | + * devgen always returns the list of children in the root | |
| 66 | + * directory. thus it follows (i) when c is the root and (ii) otherwise. | |
| 67 | + * many other Devgens follow (i) when c is a directory and (ii) otherwise. | |
| 68 | + * | |
| 69 | + * devwalk assumes (i). it knows that devgen breaks (i) | |
| 70 | + * for children that are themselves directories, and explicitly catches them. | |
| 71 | + * | |
| 72 | + * devstat assumes (ii). if the Devgen in question follows (i) | |
| 73 | + * for this particular c, devstat will not find the necessary info. | |
| 74 | + * with our particular Devgen functions, this happens only for | |
| 75 | + * directories, so devstat makes something up, assuming | |
| 76 | + * c->name, c->qid, eve, DMDIR|0555. | |
| 77 | + * | |
| 78 | + * devdirread assumes (i). the callers have to make sure | |
| 79 | + * that the Devgen satisfies (i) for the chan being read. | |
| 80 | + */ | |
| 81 | +/* | |
| 82 | + * the zeroth element of the table MUST be the directory itself for .. | |
| 83 | +*/ | |
| 84 | +int | |
| 85 | +devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) | |
| 86 | +{ | |
| 87 | + if(tab == 0) | |
| 88 | + return -1; | |
| 89 | + if(i == DEVDOTDOT){ | |
| 90 | + /* nothing */ | |
| 91 | + }else if(name){ | |
| 92 | + for(i=1; i<ntab; i++) | |
| 93 | + if(strcmp(tab[i].name, name) == 0) | |
| 94 | + break; | |
| 95 | + if(i==ntab) | |
| 96 | + return -1; | |
| 97 | + tab += i; | |
| 98 | + }else{ | |
| 99 | + /* skip over the first element, that for . itself */ | |
| 100 | + i++; | |
| 101 | + if(i >= ntab) | |
| 102 | + return -1; | |
| 103 | + tab += i; | |
| 104 | + } | |
| 105 | + devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp); | |
| 106 | + return 1; | |
| 107 | +} | |
| 108 | + | |
| 109 | +void | |
| 110 | +devreset(void) | |
| 111 | +{ | |
| 112 | +} | |
| 113 | + | |
| 114 | +void | |
| 115 | +devinit(void) | |
| 116 | +{ | |
| 117 | +} | |
| 118 | + | |
| 119 | +void | |
| 120 | +devshutdown(void) | |
| 121 | +{ | |
| 122 | +} | |
| 123 | + | |
| 124 | +Chan* | |
| 125 | +devattach(int tc, char *spec) | |
| 126 | +{ | |
| 127 | + Chan *c; | |
| 128 | + char *buf; | |
| 129 | + | |
| 130 | + c = newchan(); | |
| 131 | + mkqid(&c->qid, 0, 0, QTDIR); | |
| 132 | + c->type = devno(tc, 0); | |
| 133 | + if(spec == nil) | |
| 134 | + spec = ""; | |
| 135 | + buf = smalloc(4+strlen(spec)+1); | |
| 136 | + sprint(buf, "#%C%s", tc, spec); | |
| 137 | + c->name = newcname(buf); | |
| 138 | + free(buf); | |
| 139 | + return c; | |
| 140 | +} | |
| 141 | + | |
| 142 | + | |
| 143 | +Chan* | |
| 144 | +devclone(Chan *c) | |
| 145 | +{ | |
| 146 | + Chan *nc; | |
| 147 | + | |
| 148 | + if(c->flag & COPEN) | |
| 149 | + panic("clone of open file type %C\n", devtab[c->type]->dc); | |
| 150 | + | |
| 151 | + nc = newchan(); | |
| 152 | + | |
| 153 | + nc->type = c->type; | |
| 154 | + nc->dev = c->dev; | |
| 155 | + nc->mode = c->mode; | |
| 156 | + nc->qid = c->qid; | |
| 157 | + nc->offset = c->offset; | |
| 158 | + nc->umh = nil; | |
| 159 | + nc->mountid = c->mountid; | |
| 160 | + nc->aux = c->aux; | |
| 161 | + nc->pgrpid = c->pgrpid; | |
| 162 | + nc->mid = c->mid; | |
| 163 | + nc->mqid = c->mqid; | |
| 164 | + nc->mcp = c->mcp; | |
| 165 | + return nc; | |
| 166 | +} | |
| 167 | + | |
| 168 | +Walkqid* | |
| 169 | +devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen) | |
| 170 | +{ | |
| 171 | + int i, j, alloc; | |
| 172 | + Walkqid *wq; | |
| 173 | + char *n; | |
| 174 | + Dir dir; | |
| 175 | + | |
| 176 | + if(nname > 0) | |
| 177 | + isdir(c); | |
| 178 | + | |
| 179 | + alloc = 0; | |
| 180 | + wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); | |
| 181 | + if(waserror()){ | |
| 182 | + if(alloc && wq->clone!=nil) | |
| 183 | + cclose(wq->clone); | |
| 184 | + free(wq); | |
| 185 | + return nil; | |
| 186 | + } | |
| 187 | + if(nc == nil){ | |
| 188 | + nc = devclone(c); | |
| 189 | + nc->type = 0; /* device doesn't know about this channel yet */ | |
| 190 | + alloc = 1; | |
| 191 | + } | |
| 192 | + wq->clone = nc; | |
| 193 | + | |
| 194 | + for(j=0; j<nname; j++){ | |
| 195 | + if(!(nc->qid.type&QTDIR)){ | |
| 196 | + if(j==0) | |
| 197 | + error(Enotdir); | |
| 198 | + goto Done; | |
| 199 | + } | |
| 200 | + n = name[j]; | |
| 201 | + if(strcmp(n, ".") == 0){ | |
| 202 | + Accept: | |
| 203 | + wq->qid[wq->nqid++] = nc->qid; | |
| 204 | + continue; | |
| 205 | + } | |
| 206 | + if(strcmp(n, "..") == 0){ | |
| 207 | + if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){ | |
| 208 | + print("devgen walk .. in dev%s %llux broken\n", | |
| 209 | + devtab[nc->type]->name, nc->qid.path); | |
| 210 | + error("broken devgen"); | |
| 211 | + } | |
| 212 | + nc->qid = dir.qid; | |
| 213 | + goto Accept; | |
| 214 | + } | |
| 215 | + /* | |
| 216 | + * Ugly problem: If we're using devgen, make sure we're | |
| 217 | + * walking the directory itself, represented by the first | |
| 218 | + * entry in the table, and not trying to step into a sub- | |
| 219 | + * directory of the table, e.g. /net/net. Devgen itself | |
| 220 | + * should take care of the problem, but it doesn't have | |
| 221 | + * the necessary information (that we're doing a walk). | |
| 222 | + */ | |
| 223 | + if(gen==devgen && nc->qid.path!=tab[0].qid.path) | |
| 224 | + goto Notfound; | |
| 225 | + for(i=0;; i++) { | |
| 226 | + switch((*gen)(nc, n, tab, ntab, i, &dir)){ | |
| 227 | + case -1: | |
| 228 | + Notfound: | |
| 229 | + if(j == 0) | |
| 230 | + error(Enonexist); | |
| 231 | + kstrcpy(up->errstr, Enonexist, ERRMAX); | |
| 232 | + goto Done; | |
| 233 | + case 0: | |
| 234 | + continue; | |
| 235 | + case 1: | |
| 236 | + if(strcmp(n, dir.name) == 0){ | |
| 237 | + nc->qid = dir.qid; | |
| 238 | + goto Accept; | |
| 239 | + } | |
| 240 | + continue; | |
| 241 | + } | |
| 242 | + } | |
| 243 | + } | |
| 244 | + /* | |
| 245 | + * We processed at least one name, so will return some data. | |
| 246 | + * If we didn't process all nname entries succesfully, we drop | |
| 247 | + * the cloned channel and return just the Qids of the walks. | |
| 248 | + */ | |
| 249 | +Done: | |
| 250 | + poperror(); | |
| 251 | + if(wq->nqid < nname){ | |
| 252 | + if(alloc) | |
| 253 | + cclose(wq->clone); | |
| 254 | + wq->clone = nil; | |
| 255 | + }else if(wq->clone){ | |
| 256 | + /* attach cloned channel to same device */ | |
| 257 | + wq->clone->type = c->type; | |
| 258 | + } | |
| 259 | + return wq; | |
| 260 | +} | |
| 261 | + | |
| 262 | +int | |
| 263 | +devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen) | |
| 264 | +{ | |
| 265 | + int i; | |
| 266 | + Dir dir; | |
| 267 | + char *p, *elem; | |
| 268 | + | |
| 269 | + for(i=0;; i++) | |
| 270 | + switch((*gen)(c, nil, tab, ntab, i, &dir)){ | |
| 271 | + case -1: | |
| 272 | + if(c->qid.type & QTDIR){ | |
| 273 | + if(c->name == nil) | |
| 274 | + elem = "???"; | |
| 275 | + else if(strcmp(c->name->s, "/") == 0) | |
| 276 | + elem = "/"; | |
| 277 | + else | |
| 278 | + for(elem=p=c->name->s; *p; p++) | |
| 279 | + if(*p == '/') | |
| 280 | + elem = p+1; | |
| 281 | + devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir); | |
| 282 | + n = convD2M(&dir, db, n); | |
| 283 | + if(n == 0) | |
| 284 | + error(Ebadarg); | |
| 285 | + return n; | |
| 286 | + } | |
| 287 | + print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path); | |
| 288 | + | |
| 289 | + error(Enonexist); | |
| 290 | + case 0: | |
| 291 | + break; | |
| 292 | + case 1: | |
| 293 | + if(c->qid.path == dir.qid.path) { | |
| 294 | + if(c->flag&CMSG) | |
| 295 | + dir.mode |= DMMOUNT; | |
| 296 | + n = convD2M(&dir, db, n); | |
| 297 | + if(n == 0) | |
| 298 | + error(Ebadarg); | |
| 299 | + return n; | |
| 300 | + } | |
| 301 | + break; | |
| 302 | + } | |
| 303 | + error(Egreg); /* not reached? */ | |
| 304 | + return -1; | |
| 305 | +} | |
| 306 | + | |
| 307 | +long | |
| 308 | +devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen) | |
| 309 | +{ | |
| 310 | + long m, dsz; | |
| 311 | + struct{ | |
| 312 | + Dir d; | |
| 313 | + char slop[100]; | |
| 314 | + }dir; | |
| 315 | + | |
| 316 | + for(m=0; m<n; c->dri++) { | |
| 317 | + switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){ | |
| 318 | + case -1: | |
| 319 | + return m; | |
| 320 | + | |
| 321 | + case 0: | |
| 322 | + break; | |
| 323 | + | |
| 324 | + case 1: | |
| 325 | + dsz = convD2M(&dir.d, (uchar*)d, n-m); | |
| 326 | + if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */ | |
| 327 | + if(m == 0) | |
| 328 | + error(Eshort); | |
| 329 | + return m; | |
| 330 | + } | |
| 331 | + m += dsz; | |
| 332 | + d += dsz; | |
| 333 | + break; | |
| 334 | + } | |
| 335 | + } | |
| 336 | + | |
| 337 | + return m; | |
| 338 | +} | |
| 339 | + | |
| 340 | +/* | |
| 341 | + * error(Eperm) if open permission not granted for up->user. | |
| 342 | + */ | |
| 343 | +void | |
| 344 | +devpermcheck(char *fileuid, ulong perm, int omode) | |
| 345 | +{ | |
| 346 | + ulong t; | |
| 347 | + static int access[] = { 0400, 0200, 0600, 0100 }; | |
| 348 | + | |
| 349 | + if(strcmp(up->user, fileuid) == 0) | |
| 350 | + perm <<= 0; | |
| 351 | + else | |
| 352 | + if(strcmp(up->user, eve) == 0) | |
| 353 | + perm <<= 3; | |
| 354 | + else | |
| 355 | + perm <<= 6; | |
| 356 | + | |
| 357 | + t = access[omode&3]; | |
| 358 | + if((t&perm) != t) | |
| 359 | + error(Eperm); | |
| 360 | +} | |
| 361 | + | |
| 362 | +Chan* | |
| 363 | +devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen) | |
| 364 | +{ | |
| 365 | + int i; | |
| 366 | + Dir dir; | |
| 367 | + | |
| 368 | + for(i=0;; i++) { | |
| 369 | + switch((*gen)(c, nil, tab, ntab, i, &dir)){ | |
| 370 | + case -1: | |
| 371 | + goto Return; | |
| 372 | + case 0: | |
| 373 | + break; | |
| 374 | + case 1: | |
| 375 | + if(c->qid.path == dir.qid.path) { | |
| 376 | + devpermcheck(dir.uid, dir.mode, omode); | |
| 377 | + goto Return; | |
| 378 | + } | |
| 379 | + break; | |
| 380 | + } | |
| 381 | + } | |
| 382 | +Return: | |
| 383 | + c->offset = 0; | |
| 384 | + if((c->qid.type&QTDIR) && omode!=OREAD) | |
| 385 | + error(Eperm); | |
| 386 | + c->mode = openmode(omode); | |
| 387 | + c->flag |= COPEN; | |
| 388 | + return c; | |
| 389 | +} | |
| 390 | + | |
| 391 | +void | |
| 392 | +devcreate(Chan *c, char *name, int mode, ulong perm) | |
| 393 | +{ | |
| 394 | + USED(c); | |
| 395 | + USED(name); | |
| 396 | + USED(mode); | |
| 397 | + USED(perm); | |
| 398 | + | |
| 399 | + error(Eperm); | |
| 400 | +} | |
| 401 | + | |
| 402 | +Block* | |
| 403 | +devbread(Chan *c, long n, ulong offset) | |
| 404 | +{ | |
| 405 | + Block *bp; | |
| 406 | + | |
| 407 | + bp = allocb(n); | |
| 408 | + if(bp == 0) | |
| 409 | + error(Enomem); | |
| 410 | + if(waserror()) { | |
| 411 | + freeb(bp); | |
| 412 | + nexterror(); | |
| 413 | + } | |
| 414 | + bp->wp += devtab[c->type]->read(c, bp->wp, n, offset); | |
| 415 | + poperror(); | |
| 416 | + return bp; | |
| 417 | +} | |
| 418 | + | |
| 419 | +long | |
| 420 | +devbwrite(Chan *c, Block *bp, ulong offset) | |
| 421 | +{ | |
| 422 | + long n; | |
| 423 | + | |
| 424 | + if(waserror()) { | |
| 425 | + freeb(bp); | |
| 426 | + nexterror(); | |
| 427 | + } | |
| 428 | + n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset); | |
| 429 | + poperror(); | |
| 430 | + freeb(bp); | |
| 431 | + | |
| 432 | + return n; | |
| 433 | +} | |
| 434 | + | |
| 435 | +void | |
| 436 | +devremove(Chan *c) | |
| 437 | +{ | |
| 438 | + USED(c); | |
| 439 | + error(Eperm); | |
| 440 | +} | |
| 441 | + | |
| 442 | +int | |
| 443 | +devwstat(Chan *c, uchar *a, int n) | |
| 444 | +{ | |
| 445 | + USED(c); | |
| 446 | + USED(a); | |
| 447 | + USED(n); | |
| 448 | + | |
| 449 | + error(Eperm); | |
| 450 | + return 0; | |
| 451 | +} | |
| 452 | + | |
| 453 | +void | |
| 454 | +devpower(int a) | |
| 455 | +{ | |
| 456 | + USED(a); | |
| 457 | + error(Eperm); | |
| 458 | +} | |
| 459 | + | |
| 460 | +int | |
| 461 | +devconfig(int a, char *b, DevConf *c) | |
| 462 | +{ | |
| 463 | + USED(a); | |
| 464 | + USED(b); | |
| 465 | + USED(c); | |
| 466 | + error(Eperm); | |
| 467 | + return 0; | |
| 468 | +} | |
| @@ -0,0 +1,1238 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#include "keyboard.h" | |
| 8 | + | |
| 9 | +void (*consdebug)(void) = nil; | |
| 10 | +void (*screenputs)(char*, int) = nil; | |
| 11 | + | |
| 12 | +Queue* kbdq; /* unprocessed console input */ | |
| 13 | +Queue* lineq; /* processed console input */ | |
| 14 | +Queue* serialoq; /* serial console output */ | |
| 15 | +Queue* kprintoq; /* console output, for /dev/kprint */ | |
| 16 | +ulong kprintinuse; /* test and set whether /dev/kprint is open */ | |
| 17 | +int iprintscreenputs = 0; | |
| 18 | + | |
| 19 | +int panicking; | |
| 20 | + | |
| 21 | +struct | |
| 22 | +{ | |
| 23 | + int exiting; | |
| 24 | + int machs; | |
| 25 | +} active; | |
| 26 | + | |
| 27 | +static struct | |
| 28 | +{ | |
| 29 | + QLock lk; | |
| 30 | + | |
| 31 | + int raw; /* true if we shouldn't process input */ | |
| 32 | + int ctl; /* number of opens to the control file */ | |
| 33 | + int x; /* index into line */ | |
| 34 | + char line[1024]; /* current input line */ | |
| 35 | + | |
| 36 | + int count; | |
| 37 | + int ctlpoff; | |
| 38 | + | |
| 39 | + /* a place to save up characters at interrupt time before dumping them in the queue */ | |
| 40 | + Lock lockputc; | |
| 41 | + char istage[1024]; | |
| 42 | + char *iw; | |
| 43 | + char *ir; | |
| 44 | + char *ie; | |
| 45 | +} kbd = { | |
| 46 | + { 0 }, | |
| 47 | + 0, | |
| 48 | + 0, | |
| 49 | + 0, | |
| 50 | + { 0 }, | |
| 51 | + 0, | |
| 52 | + 0, | |
| 53 | + { 0 }, | |
| 54 | + { 0 }, | |
| 55 | + kbd.istage, | |
| 56 | + kbd.istage, | |
| 57 | + kbd.istage + sizeof(kbd.istage), | |
| 58 | +}; | |
| 59 | + | |
| 60 | +char *sysname; | |
| 61 | +vlong fasthz; | |
| 62 | + | |
| 63 | +static void seedrand(void); | |
| 64 | +static int readtime(ulong, char*, int); | |
| 65 | +static int readbintime(char*, int); | |
| 66 | +static int writetime(char*, int); | |
| 67 | +static int writebintime(char*, int); | |
| 68 | + | |
| 69 | +enum | |
| 70 | +{ | |
| 71 | + CMreboot, | |
| 72 | + CMpanic, | |
| 73 | +}; | |
| 74 | + | |
| 75 | +Cmdtab rebootmsg[] = | |
| 76 | +{ | |
| 77 | + CMreboot, "reboot", 0, | |
| 78 | + CMpanic, "panic", 0, | |
| 79 | +}; | |
| 80 | + | |
| 81 | +int | |
| 82 | +return0(void *v) | |
| 83 | +{ | |
| 84 | + return 0; | |
| 85 | +} | |
| 86 | + | |
| 87 | +void | |
| 88 | +printinit(void) | |
| 89 | +{ | |
| 90 | + lineq = qopen(2*1024, 0, nil, nil); | |
| 91 | + if(lineq == nil) | |
| 92 | + panic("printinit"); | |
| 93 | + qnoblock(lineq, 1); | |
| 94 | + | |
| 95 | + kbdq = qopen(4*1024, 0, 0, 0); | |
| 96 | + if(kbdq == nil) | |
| 97 | + panic("kbdinit"); | |
| 98 | + qnoblock(kbdq, 1); | |
| 99 | +} | |
| 100 | + | |
| 101 | +int | |
| 102 | +consactive(void) | |
| 103 | +{ | |
| 104 | + if(serialoq) | |
| 105 | + return qlen(serialoq) > 0; | |
| 106 | + return 0; | |
| 107 | +} | |
| 108 | + | |
| 109 | +void | |
| 110 | +prflush(void) | |
| 111 | +{ | |
| 112 | +/* | |
| 113 | + ulong now; | |
| 114 | + | |
| 115 | + now = m->ticks; | |
| 116 | + while(consactive()) | |
| 117 | + if(m->ticks - now >= HZ) | |
| 118 | + break; | |
| 119 | +*/ | |
| 120 | +} | |
| 121 | + | |
| 122 | +/* | |
| 123 | + * Print a string on the console. Convert \n to \r\n for serial | |
| 124 | + * line consoles. Locking of the queues is left up to the screen | |
| 125 | + * or uart code. Multi-line messages to serial consoles may get | |
| 126 | + * interspersed with other messages. | |
| 127 | + */ | |
| 128 | +static void | |
| 129 | +putstrn0(char *str, int n, int usewrite) | |
| 130 | +{ | |
| 131 | + int m; | |
| 132 | + char *t; | |
| 133 | + | |
| 134 | + /* | |
| 135 | + * if someone is reading /dev/kprint, | |
| 136 | + * put the message there. | |
| 137 | + * if not and there's an attached bit mapped display, | |
| 138 | + * put the message there. | |
| 139 | + * | |
| 140 | + * if there's a serial line being used as a console, | |
| 141 | + * put the message there. | |
| 142 | + */ | |
| 143 | + if(kprintoq != nil && !qisclosed(kprintoq)){ | |
| 144 | + if(usewrite) | |
| 145 | + qwrite(kprintoq, str, n); | |
| 146 | + else | |
| 147 | + qiwrite(kprintoq, str, n); | |
| 148 | + }else if(screenputs != nil) | |
| 149 | + screenputs(str, n); | |
| 150 | + | |
| 151 | + if(serialoq == nil){ | |
| 152 | + uartputs(str, n); | |
| 153 | + return; | |
| 154 | + } | |
| 155 | + | |
| 156 | + while(n > 0) { | |
| 157 | + t = memchr(str, '\n', n); | |
| 158 | + if(t && !kbd.raw) { | |
| 159 | + m = t-str; | |
| 160 | + if(usewrite){ | |
| 161 | + qwrite(serialoq, str, m); | |
| 162 | + qwrite(serialoq, "\r\n", 2); | |
| 163 | + } else { | |
| 164 | + qiwrite(serialoq, str, m); | |
| 165 | + qiwrite(serialoq, "\r\n", 2); | |
| 166 | + } | |
| 167 | + n -= m+1; | |
| 168 | + str = t+1; | |
| 169 | + } else { | |
| 170 | + if(usewrite) | |
| 171 | + qwrite(serialoq, str, n); | |
| 172 | + else | |
| 173 | + qiwrite(serialoq, str, n); | |
| 174 | + break; | |
| 175 | + } | |
| 176 | + } | |
| 177 | +} | |
| 178 | + | |
| 179 | +void | |
| 180 | +putstrn(char *str, int n) | |
| 181 | +{ | |
| 182 | + putstrn0(str, n, 0); | |
| 183 | +} | |
| 184 | + | |
| 185 | +int noprint; | |
| 186 | + | |
| 187 | +int | |
| 188 | +print(char *fmt, ...) | |
| 189 | +{ | |
| 190 | + int n; | |
| 191 | + va_list arg; | |
| 192 | + char buf[PRINTSIZE]; | |
| 193 | + | |
| 194 | + if(noprint) | |
| 195 | + return -1; | |
| 196 | + | |
| 197 | + va_start(arg, fmt); | |
| 198 | + n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; | |
| 199 | + va_end(arg); | |
| 200 | + putstrn(buf, n); | |
| 201 | + | |
| 202 | + return n; | |
| 203 | +} | |
| 204 | + | |
| 205 | +int | |
| 206 | +iprint(char *fmt, ...) | |
| 207 | +{ | |
| 208 | + int n, s; | |
| 209 | + va_list arg; | |
| 210 | + char buf[PRINTSIZE]; | |
| 211 | + | |
| 212 | + s = splhi(); | |
| 213 | + va_start(arg, fmt); | |
| 214 | + n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; | |
| 215 | + va_end(arg); | |
| 216 | + if(screenputs != nil && iprintscreenputs) | |
| 217 | + screenputs(buf, n); | |
| 218 | + uartputs(buf, n); | |
| 219 | + splx(s); | |
| 220 | + | |
| 221 | + return n; | |
| 222 | +} | |
| 223 | + | |
| 224 | +void | |
| 225 | +panic(char *fmt, ...) | |
| 226 | +{ | |
| 227 | + int n; | |
| 228 | + va_list arg; | |
| 229 | + char buf[PRINTSIZE]; | |
| 230 | + | |
| 231 | + kprintoq = nil; /* don't try to write to /dev/kprint */ | |
| 232 | + | |
| 233 | + if(panicking) | |
| 234 | + for(;;); | |
| 235 | + panicking = 1; | |
| 236 | + | |
| 237 | + splhi(); | |
| 238 | + strcpy(buf, "panic: "); | |
| 239 | + va_start(arg, fmt); | |
| 240 | + n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; | |
| 241 | + va_end(arg); | |
| 242 | + buf[n] = '\n'; | |
| 243 | + uartputs(buf, n+1); | |
| 244 | + if(consdebug) | |
| 245 | + (*consdebug)(); | |
| 246 | + spllo(); | |
| 247 | + prflush(); | |
| 248 | + putstrn(buf, n+1); | |
| 249 | + dumpstack(); | |
| 250 | + | |
| 251 | + exit(1); | |
| 252 | +} | |
| 253 | + | |
| 254 | +int | |
| 255 | +pprint(char *fmt, ...) | |
| 256 | +{ | |
| 257 | + int n; | |
| 258 | + Chan *c; | |
| 259 | + va_list arg; | |
| 260 | + char buf[2*PRINTSIZE]; | |
| 261 | + | |
| 262 | + if(up == nil || up->fgrp == nil) | |
| 263 | + return 0; | |
| 264 | + | |
| 265 | + c = up->fgrp->fd[2]; | |
| 266 | + if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) | |
| 267 | + return 0; | |
| 268 | + n = sprint(buf, "%s %lud: ", up->text, up->pid); | |
| 269 | + va_start(arg, fmt); | |
| 270 | + n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; | |
| 271 | + va_end(arg); | |
| 272 | + | |
| 273 | + if(waserror()) | |
| 274 | + return 0; | |
| 275 | + devtab[c->type]->write(c, buf, n, c->offset); | |
| 276 | + poperror(); | |
| 277 | + | |
| 278 | + lock(&c->ref.lk); | |
| 279 | + c->offset += n; | |
| 280 | + unlock(&c->ref.lk); | |
| 281 | + | |
| 282 | + return n; | |
| 283 | +} | |
| 284 | + | |
| 285 | +static void | |
| 286 | +echoscreen(char *buf, int n) | |
| 287 | +{ | |
| 288 | + char *e, *p; | |
| 289 | + char ebuf[128]; | |
| 290 | + int x; | |
| 291 | + | |
| 292 | + p = ebuf; | |
| 293 | + e = ebuf + sizeof(ebuf) - 4; | |
| 294 | + while(n-- > 0){ | |
| 295 | + if(p >= e){ | |
| 296 | + screenputs(ebuf, p - ebuf); | |
| 297 | + p = ebuf; | |
| 298 | + } | |
| 299 | + x = *buf++; | |
| 300 | + if(x == 0x15){ | |
| 301 | + *p++ = '^'; | |
| 302 | + *p++ = 'U'; | |
| 303 | + *p++ = '\n'; | |
| 304 | + } else | |
| 305 | + *p++ = x; | |
| 306 | + } | |
| 307 | + if(p != ebuf) | |
| 308 | + screenputs(ebuf, p - ebuf); | |
| 309 | +} | |
| 310 | + | |
| 311 | +static void | |
| 312 | +echoserialoq(char *buf, int n) | |
| 313 | +{ | |
| 314 | + char *e, *p; | |
| 315 | + char ebuf[128]; | |
| 316 | + int x; | |
| 317 | + | |
| 318 | + p = ebuf; | |
| 319 | + e = ebuf + sizeof(ebuf) - 4; | |
| 320 | + while(n-- > 0){ | |
| 321 | + if(p >= e){ | |
| 322 | + qiwrite(serialoq, ebuf, p - ebuf); | |
| 323 | + p = ebuf; | |
| 324 | + } | |
| 325 | + x = *buf++; | |
| 326 | + if(x == '\n'){ | |
| 327 | + *p++ = '\r'; | |
| 328 | + *p++ = '\n'; | |
| 329 | + } else if(x == 0x15){ | |
| 330 | + *p++ = '^'; | |
| 331 | + *p++ = 'U'; | |
| 332 | + *p++ = '\n'; | |
| 333 | + } else | |
| 334 | + *p++ = x; | |
| 335 | + } | |
| 336 | + if(p != ebuf) | |
| 337 | + qiwrite(serialoq, ebuf, p - ebuf); | |
| 338 | +} | |
| 339 | + | |
| 340 | +static void | |
| 341 | +echo(char *buf, int n) | |
| 342 | +{ | |
| 343 | + static int ctrlt, pid; | |
| 344 | + extern ulong etext; | |
| 345 | + int x; | |
| 346 | + char *e, *p; | |
| 347 | + | |
| 348 | + e = buf+n; | |
| 349 | + for(p = buf; p < e; p++){ | |
| 350 | + switch(*p){ | |
| 351 | + case 0x10: /* ^P */ | |
| 352 | + if(cpuserver && !kbd.ctlpoff){ | |
| 353 | + active.exiting = 1; | |
| 354 | + return; | |
| 355 | + } | |
| 356 | + break; | |
| 357 | + case 0x14: /* ^T */ | |
| 358 | + ctrlt++; | |
| 359 | + if(ctrlt > 2) | |
| 360 | + ctrlt = 2; | |
| 361 | + continue; | |
| 362 | + } | |
| 363 | + | |
| 364 | + if(ctrlt != 2) | |
| 365 | + continue; | |
| 366 | + | |
| 367 | + /* ^T escapes */ | |
| 368 | + ctrlt = 0; | |
| 369 | + switch(*p){ | |
| 370 | + case 'S': | |
| 371 | + x = splhi(); | |
| 372 | + dumpstack(); | |
| 373 | + procdump(); | |
| 374 | + splx(x); | |
| 375 | + return; | |
| 376 | + case 's': | |
| 377 | + dumpstack(); | |
| 378 | + return; | |
| 379 | + case 'x': | |
| 380 | + xsummary(); | |
| 381 | + ixsummary(); | |
| 382 | + mallocsummary(); | |
| 383 | + pagersummary(); | |
| 384 | + return; | |
| 385 | + case 'd': | |
| 386 | + if(consdebug == nil) | |
| 387 | + consdebug = rdb; | |
| 388 | + else | |
| 389 | + consdebug = nil; | |
| 390 | + print("consdebug now 0x%p\n", consdebug); | |
| 391 | + return; | |
| 392 | + case 'D': | |
| 393 | + if(consdebug == nil) | |
| 394 | + consdebug = rdb; | |
| 395 | + consdebug(); | |
| 396 | + return; | |
| 397 | + case 'p': | |
| 398 | + x = spllo(); | |
| 399 | + procdump(); | |
| 400 | + splx(x); | |
| 401 | + return; | |
| 402 | + case 'q': | |
| 403 | + scheddump(); | |
| 404 | + return; | |
| 405 | + case 'k': | |
| 406 | + killbig(); | |
| 407 | + return; | |
| 408 | + case 'r': | |
| 409 | + exit(0); | |
| 410 | + return; | |
| 411 | + } | |
| 412 | + } | |
| 413 | + | |
| 414 | + qproduce(kbdq, buf, n); | |
| 415 | + if(kbd.raw) | |
| 416 | + return; | |
| 417 | + if(screenputs != nil) | |
| 418 | + echoscreen(buf, n); | |
| 419 | + if(serialoq) | |
| 420 | + echoserialoq(buf, n); | |
| 421 | +} | |
| 422 | + | |
| 423 | +/* | |
| 424 | + * Called by a uart interrupt for console input. | |
| 425 | + * | |
| 426 | + * turn '\r' into '\n' before putting it into the queue. | |
| 427 | + */ | |
| 428 | +int | |
| 429 | +kbdcr2nl(Queue *q, int ch) | |
| 430 | +{ | |
| 431 | + char *next; | |
| 432 | + | |
| 433 | + USED(q); | |
| 434 | + ilock(&kbd.lockputc); /* just a mutex */ | |
| 435 | + if(ch == '\r' && !kbd.raw) | |
| 436 | + ch = '\n'; | |
| 437 | + next = kbd.iw+1; | |
| 438 | + if(next >= kbd.ie) | |
| 439 | + next = kbd.istage; | |
| 440 | + if(next != kbd.ir){ | |
| 441 | + *kbd.iw = ch; | |
| 442 | + kbd.iw = next; | |
| 443 | + } | |
| 444 | + iunlock(&kbd.lockputc); | |
| 445 | + return 0; | |
| 446 | +} | |
| 447 | +static | |
| 448 | +void | |
| 449 | +_kbdputc(int c) | |
| 450 | +{ | |
| 451 | + Rune r; | |
| 452 | + char buf[UTFmax]; | |
| 453 | + int n; | |
| 454 | + | |
| 455 | + r = c; | |
| 456 | + n = runetochar(buf, &r); | |
| 457 | + if(n == 0) | |
| 458 | + return; | |
| 459 | + echo(buf, n); | |
| 460 | +// kbd.c = r; | |
| 461 | +// qproduce(kbdq, buf, n); | |
| 462 | +} | |
| 463 | + | |
| 464 | +/* _kbdputc, but with compose translation */ | |
| 465 | +int | |
| 466 | +kbdputc(Queue *q, int c) | |
| 467 | +{ | |
| 468 | + int i; | |
| 469 | + static int collecting, nk; | |
| 470 | + static Rune kc[5]; | |
| 471 | + | |
| 472 | + if(c == Kalt){ | |
| 473 | + collecting = 1; | |
| 474 | + nk = 0; | |
| 475 | + return; | |
| 476 | + } | |
| 477 | + | |
| 478 | + if(!collecting){ | |
| 479 | + _kbdputc(c); | |
| 480 | + return; | |
| 481 | + } | |
| 482 | + | |
| 483 | + kc[nk++] = c; | |
| 484 | + c = latin1(kc, nk); | |
| 485 | + if(c < -1) /* need more keystrokes */ | |
| 486 | + return; | |
| 487 | + if(c != -1) /* valid sequence */ | |
| 488 | + _kbdputc(c); | |
| 489 | + else | |
| 490 | + for(i=0; i<nk; i++) | |
| 491 | + _kbdputc(kc[i]); | |
| 492 | + nk = 0; | |
| 493 | + collecting = 0; | |
| 494 | + | |
| 495 | + return 0; | |
| 496 | +} | |
| 497 | + | |
| 498 | + | |
| 499 | +enum{ | |
| 500 | + Qdir, | |
| 501 | + Qbintime, | |
| 502 | + Qcons, | |
| 503 | + Qconsctl, | |
| 504 | + Qcpunote, | |
| 505 | + Qcputime, | |
| 506 | + Qdrivers, | |
| 507 | + Qkprint, | |
| 508 | + Qhostdomain, | |
| 509 | + Qhostowner, | |
| 510 | + Qnull, | |
| 511 | + Qosversion, | |
| 512 | + Qpgrpid, | |
| 513 | + Qpid, | |
| 514 | + Qppid, | |
| 515 | + Qrandom, | |
| 516 | + Qreboot, | |
| 517 | + Qsecstore, | |
| 518 | + Qsnarf, | |
| 519 | + Qswap, | |
| 520 | + Qsysname, | |
| 521 | + Qsysstat, | |
| 522 | + Qtime, | |
| 523 | + Quser, | |
| 524 | + Qzero, | |
| 525 | +}; | |
| 526 | + | |
| 527 | +enum | |
| 528 | +{ | |
| 529 | + VLNUMSIZE= 22, | |
| 530 | +}; | |
| 531 | + | |
| 532 | +static Dirtab consdir[]={ | |
| 533 | + ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, | |
| 534 | + "bintime", {Qbintime}, 24, 0664, | |
| 535 | + "cons", {Qcons}, 0, 0660, | |
| 536 | + "consctl", {Qconsctl}, 0, 0220, | |
| 537 | + "cpunote", {Qcpunote}, 0, 0444, | |
| 538 | + "cputime", {Qcputime}, 6*NUMSIZE, 0444, | |
| 539 | + "drivers", {Qdrivers}, 0, 0444, | |
| 540 | + "hostdomain", {Qhostdomain}, DOMLEN, 0664, | |
| 541 | + "hostowner", {Qhostowner}, 0, 0664, | |
| 542 | + "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440, | |
| 543 | + "null", {Qnull}, 0, 0666, | |
| 544 | + "osversion", {Qosversion}, 0, 0444, | |
| 545 | + "pgrpid", {Qpgrpid}, NUMSIZE, 0444, | |
| 546 | + "pid", {Qpid}, NUMSIZE, 0444, | |
| 547 | + "ppid", {Qppid}, NUMSIZE, 0444, | |
| 548 | + "random", {Qrandom}, 0, 0444, | |
| 549 | + "reboot", {Qreboot}, 0, 0664, | |
| 550 | + "secstore", {Qsecstore}, 0, 0666, | |
| 551 | + "snarf", {Qsnarf}, 0, 0666, | |
| 552 | + "swap", {Qswap}, 0, 0664, | |
| 553 | + "sysname", {Qsysname}, 0, 0664, | |
| 554 | + "sysstat", {Qsysstat}, 0, 0666, | |
| 555 | + "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664, | |
| 556 | + "user", {Quser}, 0, 0666, | |
| 557 | + "zero", {Qzero}, 0, 0444, | |
| 558 | +}; | |
| 559 | + | |
| 560 | +char secstorebuf[65536]; | |
| 561 | +Dirtab *secstoretab = &consdir[Qsecstore]; | |
| 562 | +Dirtab *snarftab = &consdir[Qsnarf]; | |
| 563 | + | |
| 564 | +int | |
| 565 | +readnum(ulong off, char *buf, ulong n, ulong val, int size) | |
| 566 | +{ | |
| 567 | + char tmp[64]; | |
| 568 | + | |
| 569 | + snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val); | |
| 570 | + tmp[size-1] = ' '; | |
| 571 | + if(off >= size) | |
| 572 | + return 0; | |
| 573 | + if(off+n > size) | |
| 574 | + n = size-off; | |
| 575 | + memmove(buf, tmp+off, n); | |
| 576 | + return n; | |
| 577 | +} | |
| 578 | + | |
| 579 | +int | |
| 580 | +readstr(ulong off, char *buf, ulong n, char *str) | |
| 581 | +{ | |
| 582 | + int size; | |
| 583 | + | |
| 584 | + size = strlen(str); | |
| 585 | + if(off >= size) | |
| 586 | + return 0; | |
| 587 | + if(off+n > size) | |
| 588 | + n = size-off; | |
| 589 | + memmove(buf, str+off, n); | |
| 590 | + return n; | |
| 591 | +} | |
| 592 | + | |
| 593 | +static void | |
| 594 | +consinit(void) | |
| 595 | +{ | |
| 596 | + todinit(); | |
| 597 | + randominit(); | |
| 598 | + /* | |
| 599 | + * at 115200 baud, the 1024 char buffer takes 56 ms to process, | |
| 600 | + * processing it every 22 ms should be fine | |
| 601 | + */ | |
| 602 | +/* addclock0link(kbdputcclock, 22); */ | |
| 603 | +} | |
| 604 | + | |
| 605 | +static Chan* | |
| 606 | +consattach(char *spec) | |
| 607 | +{ | |
| 608 | + return devattach('c', spec); | |
| 609 | +} | |
| 610 | + | |
| 611 | +static Walkqid* | |
| 612 | +conswalk(Chan *c, Chan *nc, char **name, int nname) | |
| 613 | +{ | |
| 614 | + return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen); | |
| 615 | +} | |
| 616 | + | |
| 617 | +static int | |
| 618 | +consstat(Chan *c, uchar *dp, int n) | |
| 619 | +{ | |
| 620 | + return devstat(c, dp, n, consdir, nelem(consdir), devgen); | |
| 621 | +} | |
| 622 | + | |
| 623 | +static Chan* | |
| 624 | +consopen(Chan *c, int omode) | |
| 625 | +{ | |
| 626 | + c->aux = nil; | |
| 627 | + c = devopen(c, omode, consdir, nelem(consdir), devgen); | |
| 628 | + switch((ulong)c->qid.path){ | |
| 629 | + case Qconsctl: | |
| 630 | + qlock(&kbd.lk); | |
| 631 | + kbd.ctl++; | |
| 632 | + qunlock(&kbd.lk); | |
| 633 | + break; | |
| 634 | + | |
| 635 | + case Qkprint: | |
| 636 | + if(tas(&kprintinuse) != 0){ | |
| 637 | + c->flag &= ~COPEN; | |
| 638 | + error(Einuse); | |
| 639 | + } | |
| 640 | + if(kprintoq == nil){ | |
| 641 | + kprintoq = qopen(8*1024, Qcoalesce, 0, 0); | |
| 642 | + if(kprintoq == nil){ | |
| 643 | + c->flag &= ~COPEN; | |
| 644 | + error(Enomem); | |
| 645 | + } | |
| 646 | + qnoblock(kprintoq, 1); | |
| 647 | + }else | |
| 648 | + qreopen(kprintoq); | |
| 649 | + c->iounit = qiomaxatomic; | |
| 650 | + break; | |
| 651 | + | |
| 652 | + case Qsecstore: | |
| 653 | + if(omode == ORDWR) | |
| 654 | + error(Eperm); | |
| 655 | + if(omode != OREAD) | |
| 656 | + memset(secstorebuf, 0, sizeof secstorebuf); | |
| 657 | + break; | |
| 658 | + | |
| 659 | + case Qsnarf: | |
| 660 | + if(omode == ORDWR) | |
| 661 | + error(Eperm); | |
| 662 | + if(omode == OREAD) | |
| 663 | + c->aux = strdup(""); | |
| 664 | + else | |
| 665 | + c->aux = mallocz(SnarfSize, 1); | |
| 666 | + break; | |
| 667 | + } | |
| 668 | + return c; | |
| 669 | +} | |
| 670 | + | |
| 671 | +static void | |
| 672 | +consclose(Chan *c) | |
| 673 | +{ | |
| 674 | + switch((ulong)c->qid.path){ | |
| 675 | + /* last close of control file turns off raw */ | |
| 676 | + case Qconsctl: | |
| 677 | + if(c->flag&COPEN){ | |
| 678 | + qlock(&kbd.lk); | |
| 679 | + if(--kbd.ctl == 0) | |
| 680 | + kbd.raw = 0; | |
| 681 | + qunlock(&kbd.lk); | |
| 682 | + } | |
| 683 | + break; | |
| 684 | + | |
| 685 | + /* close of kprint allows other opens */ | |
| 686 | + case Qkprint: | |
| 687 | + if(c->flag & COPEN){ | |
| 688 | + kprintinuse = 0; | |
| 689 | + qhangup(kprintoq, nil); | |
| 690 | + } | |
| 691 | + break; | |
| 692 | + | |
| 693 | + case Qsnarf: | |
| 694 | + if(c->mode == OWRITE) | |
| 695 | + clipwrite(c->aux); | |
| 696 | + free(c->aux); | |
| 697 | + break; | |
| 698 | + } | |
| 699 | +} | |
| 700 | + | |
| 701 | +static long | |
| 702 | +consread(Chan *c, void *buf, long n, vlong off) | |
| 703 | +{ | |
| 704 | + ulong l; | |
| 705 | + char *b, *bp; | |
| 706 | + char tmp[128]; /* must be >= 6*NUMSIZE */ | |
| 707 | + char *cbuf = buf; | |
| 708 | + int ch, i, k, id, eol; | |
| 709 | + vlong offset = off; | |
| 710 | + | |
| 711 | + if(n <= 0) | |
| 712 | + return n; | |
| 713 | + switch((ulong)c->qid.path){ | |
| 714 | + case Qdir: | |
| 715 | + return devdirread(c, buf, n, consdir, nelem(consdir), devgen); | |
| 716 | + | |
| 717 | + case Qcons: | |
| 718 | + qlock(&kbd.lk); | |
| 719 | + if(waserror()) { | |
| 720 | + qunlock(&kbd.lk); | |
| 721 | + nexterror(); | |
| 722 | + } | |
| 723 | + if(kbd.raw) { | |
| 724 | + if(qcanread(lineq)) | |
| 725 | + n = qread(lineq, buf, n); | |
| 726 | + else { | |
| 727 | + /* read as much as possible */ | |
| 728 | + do { | |
| 729 | + i = qread(kbdq, cbuf, n); | |
| 730 | + cbuf += i; | |
| 731 | + n -= i; | |
| 732 | + } while (n>0 && qcanread(kbdq)); | |
| 733 | + n = cbuf - (char*)buf; | |
| 734 | + } | |
| 735 | + } else { | |
| 736 | + while(!qcanread(lineq)) { | |
| 737 | + qread(kbdq, &kbd.line[kbd.x], 1); | |
| 738 | + ch = kbd.line[kbd.x]; | |
| 739 | + eol = 0; | |
| 740 | + switch(ch){ | |
| 741 | + case '\b': | |
| 742 | + if(kbd.x) | |
| 743 | + kbd.x--; | |
| 744 | + break; | |
| 745 | + case 0x15: | |
| 746 | + kbd.x = 0; | |
| 747 | + break; | |
| 748 | + case '\n': | |
| 749 | + case 0x04: | |
| 750 | + eol = 1; | |
| 751 | + default: | |
| 752 | + kbd.line[kbd.x++] = ch; | |
| 753 | + break; | |
| 754 | + } | |
| 755 | + if(kbd.x == sizeof(kbd.line) || eol){ | |
| 756 | + if(ch == 0x04) | |
| 757 | + kbd.x--; | |
| 758 | + qwrite(lineq, kbd.line, kbd.x); | |
| 759 | + kbd.x = 0; | |
| 760 | + } | |
| 761 | + } | |
| 762 | + n = qread(lineq, buf, n); | |
| 763 | + } | |
| 764 | + qunlock(&kbd.lk); | |
| 765 | + poperror(); | |
| 766 | + return n; | |
| 767 | + | |
| 768 | + case Qcpunote: | |
| 769 | + sleep(&up->sleep, return0, nil); | |
| 770 | + | |
| 771 | + case Qcputime: | |
| 772 | + return 0; | |
| 773 | + | |
| 774 | + case Qkprint: | |
| 775 | + return qread(kprintoq, buf, n); | |
| 776 | + | |
| 777 | + case Qpgrpid: | |
| 778 | + return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); | |
| 779 | + | |
| 780 | + case Qpid: | |
| 781 | + return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); | |
| 782 | + | |
| 783 | + case Qppid: | |
| 784 | + return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); | |
| 785 | + | |
| 786 | + case Qtime: | |
| 787 | + return readtime((ulong)offset, buf, n); | |
| 788 | + | |
| 789 | + case Qbintime: | |
| 790 | + return readbintime(buf, n); | |
| 791 | + | |
| 792 | + case Qhostowner: | |
| 793 | + return readstr((ulong)offset, buf, n, eve); | |
| 794 | + | |
| 795 | + case Qhostdomain: | |
| 796 | + return readstr((ulong)offset, buf, n, hostdomain); | |
| 797 | + | |
| 798 | + case Quser: | |
| 799 | + return readstr((ulong)offset, buf, n, up->user); | |
| 800 | + | |
| 801 | + case Qnull: | |
| 802 | + return 0; | |
| 803 | + | |
| 804 | + case Qsnarf: | |
| 805 | + if(offset == 0){ | |
| 806 | + free(c->aux); | |
| 807 | + c->aux = clipread(); | |
| 808 | + } | |
| 809 | + if(c->aux == nil) | |
| 810 | + return 0; | |
| 811 | + return readstr(offset, buf, n, c->aux); | |
| 812 | + | |
| 813 | + case Qsecstore: | |
| 814 | + return readstr(offset, buf, n, secstorebuf); | |
| 815 | + | |
| 816 | + case Qsysstat: | |
| 817 | + return 0; | |
| 818 | + | |
| 819 | + case Qswap: | |
| 820 | + return 0; | |
| 821 | + | |
| 822 | + case Qsysname: | |
| 823 | + if(sysname == nil) | |
| 824 | + return 0; | |
| 825 | + return readstr((ulong)offset, buf, n, sysname); | |
| 826 | + | |
| 827 | + case Qrandom: | |
| 828 | + return randomread(buf, n); | |
| 829 | + | |
| 830 | + case Qdrivers: | |
| 831 | + b = malloc(READSTR); | |
| 832 | + if(b == nil) | |
| 833 | + error(Enomem); | |
| 834 | + n = 0; | |
| 835 | + for(i = 0; devtab[i] != nil; i++) | |
| 836 | + n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name); | |
| 837 | + if(waserror()){ | |
| 838 | + free(b); | |
| 839 | + nexterror(); | |
| 840 | + } | |
| 841 | + n = readstr((ulong)offset, buf, n, b); | |
| 842 | + free(b); | |
| 843 | + poperror(); | |
| 844 | + return n; | |
| 845 | + | |
| 846 | + case Qzero: | |
| 847 | + memset(buf, 0, n); | |
| 848 | + return n; | |
| 849 | + | |
| 850 | + case Qosversion: | |
| 851 | + snprint(tmp, sizeof tmp, "2000"); | |
| 852 | + n = readstr((ulong)offset, buf, n, tmp); | |
| 853 | + return n; | |
| 854 | + | |
| 855 | + default: | |
| 856 | + print("consread 0x%llux\n", c->qid.path); | |
| 857 | + error(Egreg); | |
| 858 | + } | |
| 859 | + return -1; /* never reached */ | |
| 860 | +} | |
| 861 | + | |
| 862 | +static long | |
| 863 | +conswrite(Chan *c, void *va, long n, vlong off) | |
| 864 | +{ | |
| 865 | + char buf[256]; | |
| 866 | + long l, bp; | |
| 867 | + char *a = va; | |
| 868 | + int id, fd; | |
| 869 | + Chan *swc; | |
| 870 | + ulong offset = off; | |
| 871 | + Cmdbuf *cb; | |
| 872 | + Cmdtab *ct; | |
| 873 | + | |
| 874 | + switch((ulong)c->qid.path){ | |
| 875 | + case Qcons: | |
| 876 | + /* | |
| 877 | + * Can't page fault in putstrn, so copy the data locally. | |
| 878 | + */ | |
| 879 | + l = n; | |
| 880 | + while(l > 0){ | |
| 881 | + bp = l; | |
| 882 | + if(bp > sizeof buf) | |
| 883 | + bp = sizeof buf; | |
| 884 | + memmove(buf, a, bp); | |
| 885 | + putstrn0(buf, bp, 1); | |
| 886 | + a += bp; | |
| 887 | + l -= bp; | |
| 888 | + } | |
| 889 | + break; | |
| 890 | + | |
| 891 | + case Qconsctl: | |
| 892 | + if(n >= sizeof(buf)) | |
| 893 | + n = sizeof(buf)-1; | |
| 894 | + strncpy(buf, a, n); | |
| 895 | + buf[n] = 0; | |
| 896 | + for(a = buf; a;){ | |
| 897 | + if(strncmp(a, "rawon", 5) == 0){ | |
| 898 | + qlock(&kbd.lk); | |
| 899 | + if(kbd.x){ | |
| 900 | + qwrite(kbdq, kbd.line, kbd.x); | |
| 901 | + kbd.x = 0; | |
| 902 | + } | |
| 903 | + kbd.raw = 1; | |
| 904 | + qunlock(&kbd.lk); | |
| 905 | + } else if(strncmp(a, "rawoff", 6) == 0){ | |
| 906 | + qlock(&kbd.lk); | |
| 907 | + kbd.raw = 0; | |
| 908 | + kbd.x = 0; | |
| 909 | + qunlock(&kbd.lk); | |
| 910 | + } else if(strncmp(a, "ctlpon", 6) == 0){ | |
| 911 | + kbd.ctlpoff = 0; | |
| 912 | + } else if(strncmp(a, "ctlpoff", 7) == 0){ | |
| 913 | + kbd.ctlpoff = 1; | |
| 914 | + } | |
| 915 | + if(a = strchr(a, ' ')) | |
| 916 | + a++; | |
| 917 | + } | |
| 918 | + break; | |
| 919 | + | |
| 920 | + case Qtime: | |
| 921 | + if(!iseve()) | |
| 922 | + error(Eperm); | |
| 923 | + return writetime(a, n); | |
| 924 | + | |
| 925 | + case Qbintime: | |
| 926 | + if(!iseve()) | |
| 927 | + error(Eperm); | |
| 928 | + return writebintime(a, n); | |
| 929 | + | |
| 930 | + case Qhostowner: | |
| 931 | + return hostownerwrite(a, n); | |
| 932 | + | |
| 933 | + case Qhostdomain: | |
| 934 | + return hostdomainwrite(a, n); | |
| 935 | + | |
| 936 | + case Quser: | |
| 937 | + return userwrite(a, n); | |
| 938 | + | |
| 939 | + case Qnull: | |
| 940 | + break; | |
| 941 | + | |
| 942 | + case Qreboot: | |
| 943 | + if(!iseve()) | |
| 944 | + error(Eperm); | |
| 945 | + cb = parsecmd(a, n); | |
| 946 | + | |
| 947 | + if(waserror()) { | |
| 948 | + free(cb); | |
| 949 | + nexterror(); | |
| 950 | + } | |
| 951 | + ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg)); | |
| 952 | + switch(ct->index) { | |
| 953 | + case CMreboot: | |
| 954 | + rebootcmd(cb->nf-1, cb->f+1); | |
| 955 | + break; | |
| 956 | + case CMpanic: | |
| 957 | + panic("/dev/reboot"); | |
| 958 | + } | |
| 959 | + poperror(); | |
| 960 | + free(cb); | |
| 961 | + break; | |
| 962 | + | |
| 963 | + case Qsecstore: | |
| 964 | + if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf) | |
| 965 | + error(Etoobig); | |
| 966 | + secstoretab->qid.vers++; | |
| 967 | + memmove(secstorebuf+offset, va, n); | |
| 968 | + return n; | |
| 969 | + | |
| 970 | + case Qsnarf: | |
| 971 | + if(offset >= SnarfSize || offset+n >= SnarfSize) | |
| 972 | + error(Etoobig); | |
| 973 | + snarftab->qid.vers++; | |
| 974 | + memmove((uchar*)c->aux+offset, va, n); | |
| 975 | + return n; | |
| 976 | + | |
| 977 | + case Qsysstat: | |
| 978 | + n = 0; | |
| 979 | + break; | |
| 980 | + | |
| 981 | + case Qswap: | |
| 982 | + if(n >= sizeof buf) | |
| 983 | + error(Egreg); | |
| 984 | + memmove(buf, va, n); /* so we can NUL-terminate */ | |
| 985 | + buf[n] = 0; | |
| 986 | + /* start a pager if not already started */ | |
| 987 | + if(strncmp(buf, "start", 5) == 0){ | |
| 988 | + kickpager(); | |
| 989 | + break; | |
| 990 | + } | |
| 991 | + if(cpuserver && !iseve()) | |
| 992 | + error(Eperm); | |
| 993 | + if(buf[0]<'0' || '9'<buf[0]) | |
| 994 | + error(Ebadarg); | |
| 995 | + fd = strtoul(buf, 0, 0); | |
| 996 | + swc = fdtochan(fd, -1, 1, 1); | |
| 997 | + setswapchan(swc); | |
| 998 | + break; | |
| 999 | + | |
| 1000 | + case Qsysname: | |
| 1001 | + if(offset != 0) | |
| 1002 | + error(Ebadarg); | |
| 1003 | + if(n <= 0 || n >= sizeof buf) | |
| 1004 | + error(Ebadarg); | |
| 1005 | + strncpy(buf, a, n); | |
| 1006 | + buf[n] = 0; | |
| 1007 | + if(buf[n-1] == '\n') | |
| 1008 | + buf[n-1] = 0; | |
| 1009 | + kstrdup(&sysname, buf); | |
| 1010 | + break; | |
| 1011 | + | |
| 1012 | + default: | |
| 1013 | + print("conswrite: 0x%llux\n", c->qid.path); | |
| 1014 | + error(Egreg); | |
| 1015 | + } | |
| 1016 | + return n; | |
| 1017 | +} | |
| 1018 | + | |
| 1019 | +Dev consdevtab = { | |
| 1020 | + 'c', | |
| 1021 | + "cons", | |
| 1022 | + | |
| 1023 | + devreset, | |
| 1024 | + consinit, | |
| 1025 | + devshutdown, | |
| 1026 | + consattach, | |
| 1027 | + conswalk, | |
| 1028 | + consstat, | |
| 1029 | + consopen, | |
| 1030 | + devcreate, | |
| 1031 | + consclose, | |
| 1032 | + consread, | |
| 1033 | + devbread, | |
| 1034 | + conswrite, | |
| 1035 | + devbwrite, | |
| 1036 | + devremove, | |
| 1037 | + devwstat, | |
| 1038 | +}; | |
| 1039 | + | |
| 1040 | +static ulong randn; | |
| 1041 | + | |
| 1042 | +static void | |
| 1043 | +seedrand(void) | |
| 1044 | +{ | |
| 1045 | + randomread((void*)&randn, sizeof(randn)); | |
| 1046 | +} | |
| 1047 | + | |
| 1048 | +// int | |
| 1049 | +// nrand(int n) | |
| 1050 | +// { | |
| 1051 | +// if(randn == 0) | |
| 1052 | +// seedrand(); | |
| 1053 | +// randn = randn*1103515245 + 12345 + fastticks(0); | |
| 1054 | +// return (randn>>16) % n; | |
| 1055 | +// } | |
| 1056 | + | |
| 1057 | +int | |
| 1058 | +rand(void) | |
| 1059 | +{ | |
| 1060 | + nrand(1); | |
| 1061 | + return randn; | |
| 1062 | +} | |
| 1063 | + | |
| 1064 | +/* static uvlong uvorder = 0x0001020304050607ULL; */ | |
| 1065 | +static uvlong uvorder = (uvlong)0x0001020304050607; | |
| 1066 | + | |
| 1067 | +static uchar* | |
| 1068 | +le2vlong(vlong *to, uchar *f) | |
| 1069 | +{ | |
| 1070 | + uchar *t, *o; | |
| 1071 | + int i; | |
| 1072 | + | |
| 1073 | + t = (uchar*)to; | |
| 1074 | + o = (uchar*)&uvorder; | |
| 1075 | + for(i = 0; i < sizeof(vlong); i++) | |
| 1076 | + t[o[i]] = f[i]; | |
| 1077 | + return f+sizeof(vlong); | |
| 1078 | +} | |
| 1079 | + | |
| 1080 | +static uchar* | |
| 1081 | +vlong2le(uchar *t, vlong from) | |
| 1082 | +{ | |
| 1083 | + uchar *f, *o; | |
| 1084 | + int i; | |
| 1085 | + | |
| 1086 | + f = (uchar*)&from; | |
| 1087 | + o = (uchar*)&uvorder; | |
| 1088 | + for(i = 0; i < sizeof(vlong); i++) | |
| 1089 | + t[i] = f[o[i]]; | |
| 1090 | + return t+sizeof(vlong); | |
| 1091 | +} | |
| 1092 | + | |
| 1093 | +static long order = 0x00010203; | |
| 1094 | + | |
| 1095 | +static uchar* | |
| 1096 | +le2long(long *to, uchar *f) | |
| 1097 | +{ | |
| 1098 | + uchar *t, *o; | |
| 1099 | + int i; | |
| 1100 | + | |
| 1101 | + t = (uchar*)to; | |
| 1102 | + o = (uchar*)ℴ | |
| 1103 | + for(i = 0; i < sizeof(long); i++) | |
| 1104 | + t[o[i]] = f[i]; | |
| 1105 | + return f+sizeof(long); | |
| 1106 | +} | |
| 1107 | + | |
| 1108 | +static uchar* | |
| 1109 | +long2le(uchar *t, long from) | |
| 1110 | +{ | |
| 1111 | + uchar *f, *o; | |
| 1112 | + int i; | |
| 1113 | + | |
| 1114 | + f = (uchar*)&from; | |
| 1115 | + o = (uchar*)ℴ | |
| 1116 | + for(i = 0; i < sizeof(long); i++) | |
| 1117 | + t[i] = f[o[i]]; | |
| 1118 | + return t+sizeof(long); | |
| 1119 | +} | |
| 1120 | + | |
| 1121 | +char *Ebadtimectl = "bad time control"; | |
| 1122 | + | |
| 1123 | +/* | |
| 1124 | + * like the old #c/time but with added info. Return | |
| 1125 | + * | |
| 1126 | + * secs nanosecs fastticks fasthz | |
| 1127 | + */ | |
| 1128 | +static int | |
| 1129 | +readtime(ulong off, char *buf, int n) | |
| 1130 | +{ | |
| 1131 | + vlong nsec, ticks; | |
| 1132 | + long sec; | |
| 1133 | + char str[7*NUMSIZE]; | |
| 1134 | + | |
| 1135 | + nsec = todget(&ticks); | |
| 1136 | + if(fasthz == (vlong)0) | |
| 1137 | + fastticks((uvlong*)&fasthz); | |
| 1138 | + sec = nsec/((uvlong) 1000000000); | |
| 1139 | + snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", | |
| 1140 | + NUMSIZE-1, sec, | |
| 1141 | + VLNUMSIZE-1, nsec, | |
| 1142 | + VLNUMSIZE-1, ticks, | |
| 1143 | + VLNUMSIZE-1, fasthz); | |
| 1144 | + return readstr(off, buf, n, str); | |
| 1145 | +} | |
| 1146 | + | |
| 1147 | +/* | |
| 1148 | + * set the time in seconds | |
| 1149 | + */ | |
| 1150 | +static int | |
| 1151 | +writetime(char *buf, int n) | |
| 1152 | +{ | |
| 1153 | + char b[13]; | |
| 1154 | + long i; | |
| 1155 | + vlong now; | |
| 1156 | + | |
| 1157 | + if(n >= sizeof(b)) | |
| 1158 | + error(Ebadtimectl); | |
| 1159 | + strncpy(b, buf, n); | |
| 1160 | + b[n] = 0; | |
| 1161 | + i = strtol(b, 0, 0); | |
| 1162 | + if(i <= 0) | |
| 1163 | + error(Ebadtimectl); | |
| 1164 | + now = i*((vlong) 1000000000); | |
| 1165 | + todset(now, 0, 0); | |
| 1166 | + return n; | |
| 1167 | +} | |
| 1168 | + | |
| 1169 | +/* | |
| 1170 | + * read binary time info. all numbers are little endian. | |
| 1171 | + * ticks and nsec are syncronized. | |
| 1172 | + */ | |
| 1173 | +static int | |
| 1174 | +readbintime(char *buf, int n) | |
| 1175 | +{ | |
| 1176 | + int i; | |
| 1177 | + vlong nsec, ticks; | |
| 1178 | + uchar *b = (uchar*)buf; | |
| 1179 | + | |
| 1180 | + i = 0; | |
| 1181 | + if(fasthz == (vlong)0) | |
| 1182 | + fastticks((uvlong*)&fasthz); | |
| 1183 | + nsec = todget(&ticks); | |
| 1184 | + if(n >= 3*sizeof(uvlong)){ | |
| 1185 | + vlong2le(b+2*sizeof(uvlong), fasthz); | |
| 1186 | + i += sizeof(uvlong); | |
| 1187 | + } | |
| 1188 | + if(n >= 2*sizeof(uvlong)){ | |
| 1189 | + vlong2le(b+sizeof(uvlong), ticks); | |
| 1190 | + i += sizeof(uvlong); | |
| 1191 | + } | |
| 1192 | + if(n >= 8){ | |
| 1193 | + vlong2le(b, nsec); | |
| 1194 | + i += sizeof(vlong); | |
| 1195 | + } | |
| 1196 | + return i; | |
| 1197 | +} | |
| 1198 | + | |
| 1199 | +/* | |
| 1200 | + * set any of the following | |
| 1201 | + * - time in nsec | |
| 1202 | + * - nsec trim applied over some seconds | |
| 1203 | + * - clock frequency | |
| 1204 | + */ | |
| 1205 | +static int | |
| 1206 | +writebintime(char *buf, int n) | |
| 1207 | +{ | |
| 1208 | + uchar *p; | |
| 1209 | + vlong delta; | |
| 1210 | + long period; | |
| 1211 | + | |
| 1212 | + n--; | |
| 1213 | + p = (uchar*)buf + 1; | |
| 1214 | + switch(*buf){ | |
| 1215 | + case 'n': | |
| 1216 | + if(n < sizeof(vlong)) | |
| 1217 | + error(Ebadtimectl); | |
| 1218 | + le2vlong(&delta, p); | |
| 1219 | + todset(delta, 0, 0); | |
| 1220 | + break; | |
| 1221 | + case 'd': | |
| 1222 | + if(n < sizeof(vlong)+sizeof(long)) | |
| 1223 | + error(Ebadtimectl); | |
| 1224 | + p = le2vlong(&delta, p); | |
| 1225 | + le2long(&period, p); | |
| 1226 | + todset(-1, delta, period); | |
| 1227 | + break; | |
| 1228 | + case 'f': | |
| 1229 | + if(n < sizeof(uvlong)) | |
| 1230 | + error(Ebadtimectl); | |
| 1231 | + le2vlong(&fasthz, p); | |
| 1232 | + todsetfreq(fasthz); | |
| 1233 | + break; | |
| 1234 | + } | |
| 1235 | + return n; | |
| 1236 | +} | |
| 1237 | + | |
| 1238 | + | |
| @@ -0,0 +1,2100 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#define Image IMAGE | |
| 8 | +#include <draw.h> | |
| 9 | +#include <memdraw.h> | |
| 10 | +#include <memlayer.h> | |
| 11 | +#include <cursor.h> | |
| 12 | +#include "screen.h" | |
| 13 | + | |
| 14 | +enum | |
| 15 | +{ | |
| 16 | + Qtopdir = 0, | |
| 17 | + Qnew, | |
| 18 | + Q3rd, | |
| 19 | + Q2nd, | |
| 20 | + Qcolormap, | |
| 21 | + Qctl, | |
| 22 | + Qdata, | |
| 23 | + Qrefresh, | |
| 24 | +}; | |
| 25 | + | |
| 26 | +/* | |
| 27 | + * Qid path is: | |
| 28 | + * 4 bits of file type (qids above) | |
| 29 | + * 24 bits of mux slot number +1; 0 means not attached to client | |
| 30 | + */ | |
| 31 | +#define QSHIFT 4 /* location in qid of client # */ | |
| 32 | + | |
| 33 | +#define QID(q) ((((ulong)(q).path)&0x0000000F)>>0) | |
| 34 | +#define CLIENTPATH(q) ((((ulong)q)&0x7FFFFFF0)>>QSHIFT) | |
| 35 | +#define CLIENT(q) CLIENTPATH((q).path) | |
| 36 | + | |
| 37 | +#define NHASH (1<<5) | |
| 38 | +#define HASHMASK (NHASH-1) | |
| 39 | +#define IOUNIT (64*1024) | |
| 40 | + | |
| 41 | +typedef struct Client Client; | |
| 42 | +typedef struct Draw Draw; | |
| 43 | +typedef struct DImage DImage; | |
| 44 | +typedef struct DScreen DScreen; | |
| 45 | +typedef struct CScreen CScreen; | |
| 46 | +typedef struct FChar FChar; | |
| 47 | +typedef struct Refresh Refresh; | |
| 48 | +typedef struct Refx Refx; | |
| 49 | +typedef struct DName DName; | |
| 50 | + | |
| 51 | +ulong blanktime = 30; /* in minutes; a half hour */ | |
| 52 | + | |
| 53 | +struct Draw | |
| 54 | +{ | |
| 55 | + QLock lk; | |
| 56 | + int clientid; | |
| 57 | + int nclient; | |
| 58 | + Client** client; | |
| 59 | + int nname; | |
| 60 | + DName* name; | |
| 61 | + int vers; | |
| 62 | + int softscreen; | |
| 63 | + int blanked; /* screen turned off */ | |
| 64 | + ulong blanktime; /* time of last operation */ | |
| 65 | + ulong savemap[3*256]; | |
| 66 | +}; | |
| 67 | + | |
| 68 | +struct Client | |
| 69 | +{ | |
| 70 | + Ref r; | |
| 71 | + DImage* dimage[NHASH]; | |
| 72 | + CScreen* cscreen; | |
| 73 | + Refresh* refresh; | |
| 74 | + Rendez refrend; | |
| 75 | + uchar* readdata; | |
| 76 | + int nreaddata; | |
| 77 | + int busy; | |
| 78 | + int clientid; | |
| 79 | + int slot; | |
| 80 | + int refreshme; | |
| 81 | + int infoid; | |
| 82 | + int op; | |
| 83 | +}; | |
| 84 | + | |
| 85 | +struct Refresh | |
| 86 | +{ | |
| 87 | + DImage* dimage; | |
| 88 | + Rectangle r; | |
| 89 | + Refresh* next; | |
| 90 | +}; | |
| 91 | + | |
| 92 | +struct Refx | |
| 93 | +{ | |
| 94 | + Client* client; | |
| 95 | + DImage* dimage; | |
| 96 | +}; | |
| 97 | + | |
| 98 | +struct DName | |
| 99 | +{ | |
| 100 | + char *name; | |
| 101 | + Client *client; | |
| 102 | + DImage* dimage; | |
| 103 | + int vers; | |
| 104 | +}; | |
| 105 | + | |
| 106 | +struct FChar | |
| 107 | +{ | |
| 108 | + int minx; /* left edge of bits */ | |
| 109 | + int maxx; /* right edge of bits */ | |
| 110 | + uchar miny; /* first non-zero scan-line */ | |
| 111 | + uchar maxy; /* last non-zero scan-line + 1 */ | |
| 112 | + schar left; /* offset of baseline */ | |
| 113 | + uchar width; /* width of baseline */ | |
| 114 | +}; | |
| 115 | + | |
| 116 | +/* | |
| 117 | + * Reference counts in DImages: | |
| 118 | + * one per open by original client | |
| 119 | + * one per screen image or fill | |
| 120 | + * one per image derived from this one by name | |
| 121 | + */ | |
| 122 | +struct DImage | |
| 123 | +{ | |
| 124 | + int id; | |
| 125 | + int ref; | |
| 126 | + char *name; | |
| 127 | + int vers; | |
| 128 | + Memimage* image; | |
| 129 | + int ascent; | |
| 130 | + int nfchar; | |
| 131 | + FChar* fchar; | |
| 132 | + DScreen* dscreen; /* 0 if not a window */ | |
| 133 | + DImage* fromname; /* image this one is derived from, by name */ | |
| 134 | + DImage* next; | |
| 135 | +}; | |
| 136 | + | |
| 137 | +struct CScreen | |
| 138 | +{ | |
| 139 | + DScreen* dscreen; | |
| 140 | + CScreen* next; | |
| 141 | +}; | |
| 142 | + | |
| 143 | +struct DScreen | |
| 144 | +{ | |
| 145 | + int id; | |
| 146 | + int public; | |
| 147 | + int ref; | |
| 148 | + DImage *dimage; | |
| 149 | + DImage *dfill; | |
| 150 | + Memscreen* screen; | |
| 151 | + Client* owner; | |
| 152 | + DScreen* next; | |
| 153 | +}; | |
| 154 | + | |
| 155 | +static Draw sdraw; | |
| 156 | +static Memimage *screenimage; | |
| 157 | +static Memdata screendata; | |
| 158 | +static Rectangle flushrect; | |
| 159 | +static int waste; | |
| 160 | +static DScreen* dscreen; | |
| 161 | +extern void flushmemscreen(Rectangle); | |
| 162 | + void drawmesg(Client*, void*, int); | |
| 163 | + void drawuninstall(Client*, int); | |
| 164 | + void drawfreedimage(DImage*); | |
| 165 | + Client* drawclientofpath(ulong); | |
| 166 | + | |
| 167 | +static char Enodrawimage[] = "unknown id for draw image"; | |
| 168 | +static char Enodrawscreen[] = "unknown id for draw screen"; | |
| 169 | +static char Eshortdraw[] = "short draw message"; | |
| 170 | +static char Eshortread[] = "draw read too short"; | |
| 171 | +static char Eimageexists[] = "image id in use"; | |
| 172 | +static char Escreenexists[] = "screen id in use"; | |
| 173 | +static char Edrawmem[] = "image memory allocation failed"; | |
| 174 | +static char Ereadoutside[] = "readimage outside image"; | |
| 175 | +static char Ewriteoutside[] = "writeimage outside image"; | |
| 176 | +static char Enotfont[] = "image not a font"; | |
| 177 | +static char Eindex[] = "character index out of range"; | |
| 178 | +static char Enoclient[] = "no such draw client"; | |
| 179 | +static char Edepth[] = "image has bad depth"; | |
| 180 | +static char Enameused[] = "image name in use"; | |
| 181 | +static char Enoname[] = "no image with that name"; | |
| 182 | +static char Eoldname[] = "named image no longer valid"; | |
| 183 | +static char Enamed[] = "image already has name"; | |
| 184 | +static char Ewrongname[] = "wrong name for image"; | |
| 185 | + | |
| 186 | +static int | |
| 187 | +drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp) | |
| 188 | +{ | |
| 189 | + int t; | |
| 190 | + Qid q; | |
| 191 | + ulong path; | |
| 192 | + Client *cl; | |
| 193 | + | |
| 194 | + USED(name); | |
| 195 | + USED(dt); | |
| 196 | + USED(ndt); | |
| 197 | + | |
| 198 | + q.vers = 0; | |
| 199 | + | |
| 200 | + if(s == DEVDOTDOT){ | |
| 201 | + switch(QID(c->qid)){ | |
| 202 | + case Qtopdir: | |
| 203 | + case Q2nd: | |
| 204 | + mkqid(&q, Qtopdir, 0, QTDIR); | |
| 205 | + devdir(c, q, "#i", 0, eve, 0500, dp); | |
| 206 | + break; | |
| 207 | + case Q3rd: | |
| 208 | + cl = drawclientofpath(c->qid.path); | |
| 209 | + if(cl == nil) | |
| 210 | + strcpy(up->genbuf, "??"); | |
| 211 | + else | |
| 212 | + sprint(up->genbuf, "%d", cl->clientid); | |
| 213 | + mkqid(&q, Q2nd, 0, QTDIR); | |
| 214 | + devdir(c, q, up->genbuf, 0, eve, 0500, dp); | |
| 215 | + break; | |
| 216 | + default: | |
| 217 | + panic("drawwalk %llux", c->qid.path); | |
| 218 | + } | |
| 219 | + return 1; | |
| 220 | + } | |
| 221 | + | |
| 222 | + /* | |
| 223 | + * Top level directory contains the name of the device. | |
| 224 | + */ | |
| 225 | + t = QID(c->qid); | |
| 226 | + if(t == Qtopdir){ | |
| 227 | + switch(s){ | |
| 228 | + case 0: | |
| 229 | + mkqid(&q, Q2nd, 0, QTDIR); | |
| 230 | + devdir(c, q, "draw", 0, eve, 0555, dp); | |
| 231 | + break; | |
| 232 | + default: | |
| 233 | + return -1; | |
| 234 | + } | |
| 235 | + return 1; | |
| 236 | + } | |
| 237 | + | |
| 238 | + /* | |
| 239 | + * Second level contains "new" plus all the clients. | |
| 240 | + */ | |
| 241 | + if(t == Q2nd || t == Qnew){ | |
| 242 | + if(s == 0){ | |
| 243 | + mkqid(&q, Qnew, 0, QTFILE); | |
| 244 | + devdir(c, q, "new", 0, eve, 0666, dp); | |
| 245 | + } | |
| 246 | + else if(s <= sdraw.nclient){ | |
| 247 | + cl = sdraw.client[s-1]; | |
| 248 | + if(cl == 0) | |
| 249 | + return 0; | |
| 250 | + sprint(up->genbuf, "%d", cl->clientid); | |
| 251 | + mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR); | |
| 252 | + devdir(c, q, up->genbuf, 0, eve, 0555, dp); | |
| 253 | + return 1; | |
| 254 | + } | |
| 255 | + else | |
| 256 | + return -1; | |
| 257 | + return 1; | |
| 258 | + } | |
| 259 | + | |
| 260 | + /* | |
| 261 | + * Third level. | |
| 262 | + */ | |
| 263 | + path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */ | |
| 264 | + q.vers = c->qid.vers; | |
| 265 | + q.type = QTFILE; | |
| 266 | + switch(s){ | |
| 267 | + case 0: | |
| 268 | + q.path = path|Qcolormap; | |
| 269 | + devdir(c, q, "colormap", 0, eve, 0600, dp); | |
| 270 | + break; | |
| 271 | + case 1: | |
| 272 | + q.path = path|Qctl; | |
| 273 | + devdir(c, q, "ctl", 0, eve, 0600, dp); | |
| 274 | + break; | |
| 275 | + case 2: | |
| 276 | + q.path = path|Qdata; | |
| 277 | + devdir(c, q, "data", 0, eve, 0600, dp); | |
| 278 | + break; | |
| 279 | + case 3: | |
| 280 | + q.path = path|Qrefresh; | |
| 281 | + devdir(c, q, "refresh", 0, eve, 0400, dp); | |
| 282 | + break; | |
| 283 | + default: | |
| 284 | + return -1; | |
| 285 | + } | |
| 286 | + return 1; | |
| 287 | +} | |
| 288 | + | |
| 289 | +static | |
| 290 | +int | |
| 291 | +drawrefactive(void *a) | |
| 292 | +{ | |
| 293 | + Client *c; | |
| 294 | + | |
| 295 | + c = a; | |
| 296 | + return c->refreshme || c->refresh!=0; | |
| 297 | +} | |
| 298 | + | |
| 299 | +static | |
| 300 | +void | |
| 301 | +drawrefreshscreen(DImage *l, Client *client) | |
| 302 | +{ | |
| 303 | + while(l != nil && l->dscreen == nil) | |
| 304 | + l = l->fromname; | |
| 305 | + if(l != nil && l->dscreen->owner != client) | |
| 306 | + l->dscreen->owner->refreshme = 1; | |
| 307 | +} | |
| 308 | + | |
| 309 | +static | |
| 310 | +void | |
| 311 | +drawrefresh(Memimage *m, Rectangle r, void *v) | |
| 312 | +{ | |
| 313 | + Refx *x; | |
| 314 | + DImage *d; | |
| 315 | + Client *c; | |
| 316 | + Refresh *ref; | |
| 317 | + | |
| 318 | + USED(m); | |
| 319 | + | |
| 320 | + if(v == 0) | |
| 321 | + return; | |
| 322 | + x = v; | |
| 323 | + c = x->client; | |
| 324 | + d = x->dimage; | |
| 325 | + for(ref=c->refresh; ref; ref=ref->next) | |
| 326 | + if(ref->dimage == d){ | |
| 327 | + combinerect(&ref->r, r); | |
| 328 | + return; | |
| 329 | + } | |
| 330 | + ref = malloc(sizeof(Refresh)); | |
| 331 | + if(ref){ | |
| 332 | + ref->dimage = d; | |
| 333 | + ref->r = r; | |
| 334 | + ref->next = c->refresh; | |
| 335 | + c->refresh = ref; | |
| 336 | + } | |
| 337 | +} | |
| 338 | + | |
| 339 | +static void | |
| 340 | +addflush(Rectangle r) | |
| 341 | +{ | |
| 342 | + int abb, ar, anbb; | |
| 343 | + Rectangle nbb; | |
| 344 | + | |
| 345 | + if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) | |
| 346 | + return; | |
| 347 | + | |
| 348 | + if(flushrect.min.x >= flushrect.max.x){ | |
| 349 | + flushrect = r; | |
| 350 | + waste = 0; | |
| 351 | + return; | |
| 352 | + } | |
| 353 | + nbb = flushrect; | |
| 354 | + combinerect(&nbb, r); | |
| 355 | + ar = Dx(r)*Dy(r); | |
| 356 | + abb = Dx(flushrect)*Dy(flushrect); | |
| 357 | + anbb = Dx(nbb)*Dy(nbb); | |
| 358 | + /* | |
| 359 | + * Area of new waste is area of new bb minus area of old bb, | |
| 360 | + * less the area of the new segment, which we assume is not waste. | |
| 361 | + * This could be negative, but that's OK. | |
| 362 | + */ | |
| 363 | + waste += anbb-abb - ar; | |
| 364 | + if(waste < 0) | |
| 365 | + waste = 0; | |
| 366 | + /* | |
| 367 | + * absorb if: | |
| 368 | + * total area is small | |
| 369 | + * waste is less than half total area | |
| 370 | + * rectangles touch | |
| 371 | + */ | |
| 372 | + if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){ | |
| 373 | + flushrect = nbb; | |
| 374 | + return; | |
| 375 | + } | |
| 376 | + /* emit current state */ | |
| 377 | + if(flushrect.min.x < flushrect.max.x) | |
| 378 | + flushmemscreen(flushrect); | |
| 379 | + flushrect = r; | |
| 380 | + waste = 0; | |
| 381 | +} | |
| 382 | + | |
| 383 | +static | |
| 384 | +void | |
| 385 | +dstflush(int dstid, Memimage *dst, Rectangle r) | |
| 386 | +{ | |
| 387 | + Memlayer *l; | |
| 388 | + | |
| 389 | + if(dstid == 0){ | |
| 390 | + combinerect(&flushrect, r); | |
| 391 | + return; | |
| 392 | + } | |
| 393 | + /* how can this happen? -rsc, dec 12 2002 */ | |
| 394 | + if(dst == 0){ | |
| 395 | + print("nil dstflush\n"); | |
| 396 | + return; | |
| 397 | + } | |
| 398 | + l = dst->layer; | |
| 399 | + if(l == nil) | |
| 400 | + return; | |
| 401 | + do{ | |
| 402 | + if(l->screen->image->data != screenimage->data) | |
| 403 | + return; | |
| 404 | + r = rectaddpt(r, l->delta); | |
| 405 | + l = l->screen->image->layer; | |
| 406 | + }while(l); | |
| 407 | + addflush(r); | |
| 408 | +} | |
| 409 | + | |
| 410 | +void | |
| 411 | +drawflush(void) | |
| 412 | +{ | |
| 413 | + if(flushrect.min.x < flushrect.max.x) | |
| 414 | + flushmemscreen(flushrect); | |
| 415 | + flushrect = Rect(10000, 10000, -10000, -10000); | |
| 416 | +} | |
| 417 | + | |
| 418 | +void | |
| 419 | +drawflushr(Rectangle r) | |
| 420 | +{ | |
| 421 | + qlock(&sdraw.lk); | |
| 422 | + flushmemscreen(r); | |
| 423 | + qunlock(&sdraw.lk); | |
| 424 | +} | |
| 425 | + | |
| 426 | +static | |
| 427 | +int | |
| 428 | +drawcmp(char *a, char *b, int n) | |
| 429 | +{ | |
| 430 | + if(strlen(a) != n) | |
| 431 | + return 1; | |
| 432 | + return memcmp(a, b, n); | |
| 433 | +} | |
| 434 | + | |
| 435 | +DName* | |
| 436 | +drawlookupname(int n, char *str) | |
| 437 | +{ | |
| 438 | + DName *name, *ename; | |
| 439 | + | |
| 440 | + name = sdraw.name; | |
| 441 | + ename = &name[sdraw.nname]; | |
| 442 | + for(; name<ename; name++) | |
| 443 | + if(drawcmp(name->name, str, n) == 0) | |
| 444 | + return name; | |
| 445 | + return 0; | |
| 446 | +} | |
| 447 | + | |
| 448 | +int | |
| 449 | +drawgoodname(DImage *d) | |
| 450 | +{ | |
| 451 | + DName *n; | |
| 452 | + | |
| 453 | + /* if window, validate the screen's own images */ | |
| 454 | + if(d->dscreen) | |
| 455 | + if(drawgoodname(d->dscreen->dimage) == 0 | |
| 456 | + || drawgoodname(d->dscreen->dfill) == 0) | |
| 457 | + return 0; | |
| 458 | + if(d->name == nil) | |
| 459 | + return 1; | |
| 460 | + n = drawlookupname(strlen(d->name), d->name); | |
| 461 | + if(n==nil || n->vers!=d->vers) | |
| 462 | + return 0; | |
| 463 | + return 1; | |
| 464 | +} | |
| 465 | + | |
| 466 | +DImage* | |
| 467 | +drawlookup(Client *client, int id, int checkname) | |
| 468 | +{ | |
| 469 | + DImage *d; | |
| 470 | + | |
| 471 | + d = client->dimage[id&HASHMASK]; | |
| 472 | + while(d){ | |
| 473 | + if(d->id == id){ | |
| 474 | + if(checkname && !drawgoodname(d)) | |
| 475 | + error(Eoldname); | |
| 476 | + return d; | |
| 477 | + } | |
| 478 | + d = d->next; | |
| 479 | + } | |
| 480 | + return 0; | |
| 481 | +} | |
| 482 | + | |
| 483 | +DScreen* | |
| 484 | +drawlookupdscreen(int id) | |
| 485 | +{ | |
| 486 | + DScreen *s; | |
| 487 | + | |
| 488 | + s = dscreen; | |
| 489 | + while(s){ | |
| 490 | + if(s->id == id) | |
| 491 | + return s; | |
| 492 | + s = s->next; | |
| 493 | + } | |
| 494 | + return 0; | |
| 495 | +} | |
| 496 | + | |
| 497 | +DScreen* | |
| 498 | +drawlookupscreen(Client *client, int id, CScreen **cs) | |
| 499 | +{ | |
| 500 | + CScreen *s; | |
| 501 | + | |
| 502 | + s = client->cscreen; | |
| 503 | + while(s){ | |
| 504 | + if(s->dscreen->id == id){ | |
| 505 | + *cs = s; | |
| 506 | + return s->dscreen; | |
| 507 | + } | |
| 508 | + s = s->next; | |
| 509 | + } | |
| 510 | + error(Enodrawscreen); | |
| 511 | + return 0; | |
| 512 | +} | |
| 513 | + | |
| 514 | +Memimage* | |
| 515 | +drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen) | |
| 516 | +{ | |
| 517 | + DImage *d; | |
| 518 | + | |
| 519 | + d = malloc(sizeof(DImage)); | |
| 520 | + if(d == 0) | |
| 521 | + return 0; | |
| 522 | + d->id = id; | |
| 523 | + d->ref = 1; | |
| 524 | + d->name = 0; | |
| 525 | + d->vers = 0; | |
| 526 | + d->image = i; | |
| 527 | + d->nfchar = 0; | |
| 528 | + d->fchar = 0; | |
| 529 | + d->fromname = 0; | |
| 530 | + d->dscreen = dscreen; | |
| 531 | + d->next = client->dimage[id&HASHMASK]; | |
| 532 | + client->dimage[id&HASHMASK] = d; | |
| 533 | + return i; | |
| 534 | +} | |
| 535 | + | |
| 536 | +Memscreen* | |
| 537 | +drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public) | |
| 538 | +{ | |
| 539 | + Memscreen *s; | |
| 540 | + CScreen *c; | |
| 541 | + | |
| 542 | + c = malloc(sizeof(CScreen)); | |
| 543 | + if(dimage && dimage->image && dimage->image->chan == 0) | |
| 544 | + panic("bad image %p in drawinstallscreen", dimage->image); | |
| 545 | + | |
| 546 | + if(c == 0) | |
| 547 | + return 0; | |
| 548 | + if(d == 0){ | |
| 549 | + d = malloc(sizeof(DScreen)); | |
| 550 | + if(d == 0){ | |
| 551 | + free(c); | |
| 552 | + return 0; | |
| 553 | + } | |
| 554 | + s = malloc(sizeof(Memscreen)); | |
| 555 | + if(s == 0){ | |
| 556 | + free(c); | |
| 557 | + free(d); | |
| 558 | + return 0; | |
| 559 | + } | |
| 560 | + s->frontmost = 0; | |
| 561 | + s->rearmost = 0; | |
| 562 | + d->dimage = dimage; | |
| 563 | + if(dimage){ | |
| 564 | + s->image = dimage->image; | |
| 565 | + dimage->ref++; | |
| 566 | + } | |
| 567 | + d->dfill = dfill; | |
| 568 | + if(dfill){ | |
| 569 | + s->fill = dfill->image; | |
| 570 | + dfill->ref++; | |
| 571 | + } | |
| 572 | + d->ref = 0; | |
| 573 | + d->id = id; | |
| 574 | + d->screen = s; | |
| 575 | + d->public = public; | |
| 576 | + d->next = dscreen; | |
| 577 | + d->owner = client; | |
| 578 | + dscreen = d; | |
| 579 | + } | |
| 580 | + c->dscreen = d; | |
| 581 | + d->ref++; | |
| 582 | + c->next = client->cscreen; | |
| 583 | + client->cscreen = c; | |
| 584 | + return d->screen; | |
| 585 | +} | |
| 586 | + | |
| 587 | +void | |
| 588 | +drawdelname(DName *name) | |
| 589 | +{ | |
| 590 | + int i; | |
| 591 | + | |
| 592 | + i = name-sdraw.name; | |
| 593 | + memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName)); | |
| 594 | + sdraw.nname--; | |
| 595 | +} | |
| 596 | + | |
| 597 | +void | |
| 598 | +drawfreedscreen(DScreen *this) | |
| 599 | +{ | |
| 600 | + DScreen *ds, *next; | |
| 601 | + | |
| 602 | + this->ref--; | |
| 603 | + if(this->ref < 0) | |
| 604 | + print("negative ref in drawfreedscreen\n"); | |
| 605 | + if(this->ref > 0) | |
| 606 | + return; | |
| 607 | + ds = dscreen; | |
| 608 | + if(ds == this){ | |
| 609 | + dscreen = this->next; | |
| 610 | + goto Found; | |
| 611 | + } | |
| 612 | + while(next = ds->next){ /* assign = */ | |
| 613 | + if(next == this){ | |
| 614 | + ds->next = this->next; | |
| 615 | + goto Found; | |
| 616 | + } | |
| 617 | + ds = next; | |
| 618 | + } | |
| 619 | + error(Enodrawimage); | |
| 620 | + | |
| 621 | + Found: | |
| 622 | + if(this->dimage) | |
| 623 | + drawfreedimage(this->dimage); | |
| 624 | + if(this->dfill) | |
| 625 | + drawfreedimage(this->dfill); | |
| 626 | + free(this->screen); | |
| 627 | + free(this); | |
| 628 | +} | |
| 629 | + | |
| 630 | +void | |
| 631 | +drawfreedimage(DImage *dimage) | |
| 632 | +{ | |
| 633 | + int i; | |
| 634 | + Memimage *l; | |
| 635 | + DScreen *ds; | |
| 636 | + | |
| 637 | + dimage->ref--; | |
| 638 | + if(dimage->ref < 0) | |
| 639 | + print("negative ref in drawfreedimage\n"); | |
| 640 | + if(dimage->ref > 0) | |
| 641 | + return; | |
| 642 | + | |
| 643 | + /* any names? */ | |
| 644 | + for(i=0; i<sdraw.nname; ) | |
| 645 | + if(sdraw.name[i].dimage == dimage) | |
| 646 | + drawdelname(sdraw.name+i); | |
| 647 | + else | |
| 648 | + i++; | |
| 649 | + if(dimage->fromname){ /* acquired by name; owned by someone else*/ | |
| 650 | + drawfreedimage(dimage->fromname); | |
| 651 | + goto Return; | |
| 652 | + } | |
| 653 | + if(dimage->image == screenimage) /* don't free the display */ | |
| 654 | + goto Return; | |
| 655 | + ds = dimage->dscreen; | |
| 656 | + if(ds){ | |
| 657 | + l = dimage->image; | |
| 658 | + if(l->data == screenimage->data) | |
| 659 | + addflush(l->layer->screenr); | |
| 660 | + if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */ | |
| 661 | + free(l->layer->refreshptr); | |
| 662 | + l->layer->refreshptr = nil; | |
| 663 | + if(drawgoodname(dimage)) | |
| 664 | + memldelete(l); | |
| 665 | + else | |
| 666 | + memlfree(l); | |
| 667 | + drawfreedscreen(ds); | |
| 668 | + }else | |
| 669 | + freememimage(dimage->image); | |
| 670 | + Return: | |
| 671 | + free(dimage->fchar); | |
| 672 | + free(dimage); | |
| 673 | +} | |
| 674 | + | |
| 675 | +void | |
| 676 | +drawuninstallscreen(Client *client, CScreen *this) | |
| 677 | +{ | |
| 678 | + CScreen *cs, *next; | |
| 679 | + | |
| 680 | + cs = client->cscreen; | |
| 681 | + if(cs == this){ | |
| 682 | + client->cscreen = this->next; | |
| 683 | + drawfreedscreen(this->dscreen); | |
| 684 | + free(this); | |
| 685 | + return; | |
| 686 | + } | |
| 687 | + while(next = cs->next){ /* assign = */ | |
| 688 | + if(next == this){ | |
| 689 | + cs->next = this->next; | |
| 690 | + drawfreedscreen(this->dscreen); | |
| 691 | + free(this); | |
| 692 | + return; | |
| 693 | + } | |
| 694 | + cs = next; | |
| 695 | + } | |
| 696 | +} | |
| 697 | + | |
| 698 | +void | |
| 699 | +drawuninstall(Client *client, int id) | |
| 700 | +{ | |
| 701 | + DImage *d, *next; | |
| 702 | + | |
| 703 | + d = client->dimage[id&HASHMASK]; | |
| 704 | + if(d == 0) | |
| 705 | + error(Enodrawimage); | |
| 706 | + if(d->id == id){ | |
| 707 | + client->dimage[id&HASHMASK] = d->next; | |
| 708 | + drawfreedimage(d); | |
| 709 | + return; | |
| 710 | + } | |
| 711 | + while(next = d->next){ /* assign = */ | |
| 712 | + if(next->id == id){ | |
| 713 | + d->next = next->next; | |
| 714 | + drawfreedimage(next); | |
| 715 | + return; | |
| 716 | + } | |
| 717 | + d = next; | |
| 718 | + } | |
| 719 | + error(Enodrawimage); | |
| 720 | +} | |
| 721 | + | |
| 722 | +void | |
| 723 | +drawaddname(Client *client, DImage *di, int n, char *str) | |
| 724 | +{ | |
| 725 | + DName *name, *ename, *new, *t; | |
| 726 | + | |
| 727 | + name = sdraw.name; | |
| 728 | + ename = &name[sdraw.nname]; | |
| 729 | + for(; name<ename; name++) | |
| 730 | + if(drawcmp(name->name, str, n) == 0) | |
| 731 | + error(Enameused); | |
| 732 | + t = smalloc((sdraw.nname+1)*sizeof(DName)); | |
| 733 | + memmove(t, sdraw.name, sdraw.nname*sizeof(DName)); | |
| 734 | + free(sdraw.name); | |
| 735 | + sdraw.name = t; | |
| 736 | + new = &sdraw.name[sdraw.nname++]; | |
| 737 | + new->name = smalloc(n+1); | |
| 738 | + memmove(new->name, str, n); | |
| 739 | + new->name[n] = 0; | |
| 740 | + new->dimage = di; | |
| 741 | + new->client = client; | |
| 742 | + new->vers = ++sdraw.vers; | |
| 743 | +} | |
| 744 | + | |
| 745 | +Client* | |
| 746 | +drawnewclient(void) | |
| 747 | +{ | |
| 748 | + Client *cl, **cp; | |
| 749 | + int i; | |
| 750 | + | |
| 751 | + for(i=0; i<sdraw.nclient; i++){ | |
| 752 | + cl = sdraw.client[i]; | |
| 753 | + if(cl == 0) | |
| 754 | + break; | |
| 755 | + } | |
| 756 | + if(i == sdraw.nclient){ | |
| 757 | + cp = malloc((sdraw.nclient+1)*sizeof(Client*)); | |
| 758 | + if(cp == 0) | |
| 759 | + return 0; | |
| 760 | + memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*)); | |
| 761 | + free(sdraw.client); | |
| 762 | + sdraw.client = cp; | |
| 763 | + sdraw.nclient++; | |
| 764 | + cp[i] = 0; | |
| 765 | + } | |
| 766 | + cl = malloc(sizeof(Client)); | |
| 767 | + if(cl == 0) | |
| 768 | + return 0; | |
| 769 | + memset(cl, 0, sizeof(Client)); | |
| 770 | + cl->slot = i; | |
| 771 | + cl->clientid = ++sdraw.clientid; | |
| 772 | + cl->op = SoverD; | |
| 773 | + sdraw.client[i] = cl; | |
| 774 | + return cl; | |
| 775 | +} | |
| 776 | + | |
| 777 | +static int | |
| 778 | +drawclientop(Client *cl) | |
| 779 | +{ | |
| 780 | + int op; | |
| 781 | + | |
| 782 | + op = cl->op; | |
| 783 | + cl->op = SoverD; | |
| 784 | + return op; | |
| 785 | +} | |
| 786 | + | |
| 787 | +int | |
| 788 | +drawhasclients(void) | |
| 789 | +{ | |
| 790 | + /* | |
| 791 | + * if draw has ever been used, we can't resize the frame buffer, | |
| 792 | + * even if all clients have exited (nclients is cumulative); it's too | |
| 793 | + * hard to make work. | |
| 794 | + */ | |
| 795 | + return sdraw.nclient != 0; | |
| 796 | +} | |
| 797 | + | |
| 798 | +Client* | |
| 799 | +drawclientofpath(ulong path) | |
| 800 | +{ | |
| 801 | + Client *cl; | |
| 802 | + int slot; | |
| 803 | + | |
| 804 | + slot = CLIENTPATH(path); | |
| 805 | + if(slot == 0) | |
| 806 | + return nil; | |
| 807 | + cl = sdraw.client[slot-1]; | |
| 808 | + if(cl==0 || cl->clientid==0) | |
| 809 | + return nil; | |
| 810 | + return cl; | |
| 811 | +} | |
| 812 | + | |
| 813 | + | |
| 814 | +Client* | |
| 815 | +drawclient(Chan *c) | |
| 816 | +{ | |
| 817 | + Client *client; | |
| 818 | + | |
| 819 | + client = drawclientofpath(c->qid.path); | |
| 820 | + if(client == nil) | |
| 821 | + error(Enoclient); | |
| 822 | + return client; | |
| 823 | +} | |
| 824 | + | |
| 825 | +Memimage* | |
| 826 | +drawimage(Client *client, uchar *a) | |
| 827 | +{ | |
| 828 | + DImage *d; | |
| 829 | + | |
| 830 | + d = drawlookup(client, BGLONG(a), 1); | |
| 831 | + if(d == nil) | |
| 832 | + error(Enodrawimage); | |
| 833 | + return d->image; | |
| 834 | +} | |
| 835 | + | |
| 836 | +void | |
| 837 | +drawrectangle(Rectangle *r, uchar *a) | |
| 838 | +{ | |
| 839 | + r->min.x = BGLONG(a+0*4); | |
| 840 | + r->min.y = BGLONG(a+1*4); | |
| 841 | + r->max.x = BGLONG(a+2*4); | |
| 842 | + r->max.y = BGLONG(a+3*4); | |
| 843 | +} | |
| 844 | + | |
| 845 | +void | |
| 846 | +drawpoint(Point *p, uchar *a) | |
| 847 | +{ | |
| 848 | + p->x = BGLONG(a+0*4); | |
| 849 | + p->y = BGLONG(a+1*4); | |
| 850 | +} | |
| 851 | + | |
| 852 | +Point | |
| 853 | +drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op) | |
| 854 | +{ | |
| 855 | + FChar *fc; | |
| 856 | + Rectangle r; | |
| 857 | + Point sp1; | |
| 858 | + | |
| 859 | + fc = &font->fchar[index]; | |
| 860 | + r.min.x = p.x+fc->left; | |
| 861 | + r.min.y = p.y-(font->ascent-fc->miny); | |
| 862 | + r.max.x = r.min.x+(fc->maxx-fc->minx); | |
| 863 | + r.max.y = r.min.y+(fc->maxy-fc->miny); | |
| 864 | + sp1.x = sp->x+fc->left; | |
| 865 | + sp1.y = sp->y+fc->miny; | |
| 866 | + memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op); | |
| 867 | + p.x += fc->width; | |
| 868 | + sp->x += fc->width; | |
| 869 | + return p; | |
| 870 | +} | |
| 871 | + | |
| 872 | +static int | |
| 873 | +initscreenimage(void) | |
| 874 | +{ | |
| 875 | + int width, depth; | |
| 876 | + ulong chan; | |
| 877 | + void *X; | |
| 878 | + Rectangle r; | |
| 879 | + | |
| 880 | + if(screenimage != nil) | |
| 881 | + return 1; | |
| 882 | + | |
| 883 | + screendata.base = nil; | |
| 884 | + screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X); | |
| 885 | + if(screendata.bdata == nil && X == nil) | |
| 886 | + return 0; | |
| 887 | + screendata.ref = 1; | |
| 888 | + | |
| 889 | + screenimage = allocmemimaged(r, chan, &screendata, X); | |
| 890 | + if(screenimage == nil){ | |
| 891 | + /* RSC: BUG: detach screen */ | |
| 892 | + return 0; | |
| 893 | + } | |
| 894 | + | |
| 895 | + screenimage->width = width; | |
| 896 | + screenimage->clipr = r; | |
| 897 | + return 1; | |
| 898 | +} | |
| 899 | + | |
| 900 | +void | |
| 901 | +deletescreenimage(void) | |
| 902 | +{ | |
| 903 | + qlock(&sdraw.lk); | |
| 904 | + /* RSC: BUG: detach screen */ | |
| 905 | + if(screenimage) | |
| 906 | + freememimage(screenimage); | |
| 907 | + screenimage = nil; | |
| 908 | + qunlock(&sdraw.lk); | |
| 909 | +} | |
| 910 | + | |
| 911 | +static Chan* | |
| 912 | +drawattach(char *spec) | |
| 913 | +{ | |
| 914 | + qlock(&sdraw.lk); | |
| 915 | + if(!initscreenimage()){ | |
| 916 | + qunlock(&sdraw.lk); | |
| 917 | + error("no frame buffer"); | |
| 918 | + } | |
| 919 | + qunlock(&sdraw.lk); | |
| 920 | + return devattach('i', spec); | |
| 921 | +} | |
| 922 | + | |
| 923 | +static Walkqid* | |
| 924 | +drawwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 925 | +{ | |
| 926 | + if(screendata.bdata == nil) | |
| 927 | + error("no frame buffer"); | |
| 928 | + return devwalk(c, nc, name, nname, 0, 0, drawgen); | |
| 929 | +} | |
| 930 | + | |
| 931 | +static int | |
| 932 | +drawstat(Chan *c, uchar *db, int n) | |
| 933 | +{ | |
| 934 | + return devstat(c, db, n, 0, 0, drawgen); | |
| 935 | +} | |
| 936 | + | |
| 937 | +static Chan* | |
| 938 | +drawopen(Chan *c, int omode) | |
| 939 | +{ | |
| 940 | + Client *cl; | |
| 941 | + | |
| 942 | + if(c->qid.type & QTDIR){ | |
| 943 | + c = devopen(c, omode, 0, 0, drawgen); | |
| 944 | + c->iounit = IOUNIT; | |
| 945 | + } | |
| 946 | + | |
| 947 | + qlock(&sdraw.lk); | |
| 948 | + if(waserror()){ | |
| 949 | + qunlock(&sdraw.lk); | |
| 950 | + nexterror(); | |
| 951 | + } | |
| 952 | + | |
| 953 | + if(QID(c->qid) == Qnew){ | |
| 954 | + cl = drawnewclient(); | |
| 955 | + if(cl == 0) | |
| 956 | + error(Enodev); | |
| 957 | + c->qid.path = Qctl|((cl->slot+1)<<QSHIFT); | |
| 958 | + } | |
| 959 | + | |
| 960 | + switch(QID(c->qid)){ | |
| 961 | + case Qnew: | |
| 962 | + break; | |
| 963 | + | |
| 964 | + case Qctl: | |
| 965 | + cl = drawclient(c); | |
| 966 | + if(cl->busy) | |
| 967 | + error(Einuse); | |
| 968 | + cl->busy = 1; | |
| 969 | + flushrect = Rect(10000, 10000, -10000, -10000); | |
| 970 | + drawinstall(cl, 0, screenimage, 0); | |
| 971 | + incref(&cl->r); | |
| 972 | + break; | |
| 973 | + case Qcolormap: | |
| 974 | + case Qdata: | |
| 975 | + case Qrefresh: | |
| 976 | + cl = drawclient(c); | |
| 977 | + incref(&cl->r); | |
| 978 | + break; | |
| 979 | + } | |
| 980 | + qunlock(&sdraw.lk); | |
| 981 | + poperror(); | |
| 982 | + c->mode = openmode(omode); | |
| 983 | + c->flag |= COPEN; | |
| 984 | + c->offset = 0; | |
| 985 | + c->iounit = IOUNIT; | |
| 986 | + return c; | |
| 987 | +} | |
| 988 | + | |
| 989 | +static void | |
| 990 | +drawclose(Chan *c) | |
| 991 | +{ | |
| 992 | + int i; | |
| 993 | + DImage *d, **dp; | |
| 994 | + Client *cl; | |
| 995 | + Refresh *r; | |
| 996 | + | |
| 997 | + if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */ | |
| 998 | + return; | |
| 999 | + qlock(&sdraw.lk); | |
| 1000 | + if(waserror()){ | |
| 1001 | + qunlock(&sdraw.lk); | |
| 1002 | + nexterror(); | |
| 1003 | + } | |
| 1004 | + | |
| 1005 | + cl = drawclient(c); | |
| 1006 | + if(QID(c->qid) == Qctl) | |
| 1007 | + cl->busy = 0; | |
| 1008 | + if((c->flag&COPEN) && (decref(&cl->r)==0)){ | |
| 1009 | + while(r = cl->refresh){ /* assign = */ | |
| 1010 | + cl->refresh = r->next; | |
| 1011 | + free(r); | |
| 1012 | + } | |
| 1013 | + /* free names */ | |
| 1014 | + for(i=0; i<sdraw.nname; ) | |
| 1015 | + if(sdraw.name[i].client == cl) | |
| 1016 | + drawdelname(sdraw.name+i); | |
| 1017 | + else | |
| 1018 | + i++; | |
| 1019 | + while(cl->cscreen) | |
| 1020 | + drawuninstallscreen(cl, cl->cscreen); | |
| 1021 | + /* all screens are freed, so now we can free images */ | |
| 1022 | + dp = cl->dimage; | |
| 1023 | + for(i=0; i<NHASH; i++){ | |
| 1024 | + while((d = *dp) != nil){ | |
| 1025 | + *dp = d->next; | |
| 1026 | + drawfreedimage(d); | |
| 1027 | + } | |
| 1028 | + dp++; | |
| 1029 | + } | |
| 1030 | + sdraw.client[cl->slot] = 0; | |
| 1031 | + drawflush(); /* to erase visible, now dead windows */ | |
| 1032 | + free(cl); | |
| 1033 | + } | |
| 1034 | + qunlock(&sdraw.lk); | |
| 1035 | + poperror(); | |
| 1036 | +} | |
| 1037 | + | |
| 1038 | +long | |
| 1039 | +drawread(Chan *c, void *a, long n, vlong off) | |
| 1040 | +{ | |
| 1041 | + int index, m; | |
| 1042 | + ulong red, green, blue; | |
| 1043 | + Client *cl; | |
| 1044 | + uchar *p; | |
| 1045 | + Refresh *r; | |
| 1046 | + DImage *di; | |
| 1047 | + Memimage *i; | |
| 1048 | + ulong offset = off; | |
| 1049 | + char buf[16]; | |
| 1050 | + | |
| 1051 | + if(c->qid.type & QTDIR) | |
| 1052 | + return devdirread(c, a, n, 0, 0, drawgen); | |
| 1053 | + cl = drawclient(c); | |
| 1054 | + qlock(&sdraw.lk); | |
| 1055 | + if(waserror()){ | |
| 1056 | + qunlock(&sdraw.lk); | |
| 1057 | + nexterror(); | |
| 1058 | + } | |
| 1059 | + switch(QID(c->qid)){ | |
| 1060 | + case Qctl: | |
| 1061 | + if(n < 12*12) | |
| 1062 | + error(Eshortread); | |
| 1063 | + if(cl->infoid < 0) | |
| 1064 | + error(Enodrawimage); | |
| 1065 | + if(cl->infoid == 0){ | |
| 1066 | + i = screenimage; | |
| 1067 | + if(i == nil) | |
| 1068 | + error(Enodrawimage); | |
| 1069 | + }else{ | |
| 1070 | + di = drawlookup(cl, cl->infoid, 1); | |
| 1071 | + if(di == nil) | |
| 1072 | + error(Enodrawimage); | |
| 1073 | + i = di->image; | |
| 1074 | + } | |
| 1075 | + n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ", | |
| 1076 | + cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl, | |
| 1077 | + i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y, | |
| 1078 | + i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y); | |
| 1079 | + cl->infoid = -1; | |
| 1080 | + break; | |
| 1081 | + | |
| 1082 | + case Qcolormap: | |
| 1083 | + drawactive(1); /* to restore map from backup */ | |
| 1084 | + p = malloc(4*12*256+1); | |
| 1085 | + if(p == 0) | |
| 1086 | + error(Enomem); | |
| 1087 | + m = 0; | |
| 1088 | + for(index = 0; index < 256; index++){ | |
| 1089 | + getcolor(index, &red, &green, &blue); | |
| 1090 | + m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24); | |
| 1091 | + } | |
| 1092 | + n = readstr(offset, a, n, (char*)p); | |
| 1093 | + free(p); | |
| 1094 | + break; | |
| 1095 | + | |
| 1096 | + case Qdata: | |
| 1097 | + if(cl->readdata == nil) | |
| 1098 | + error("no draw data"); | |
| 1099 | + if(n < cl->nreaddata) | |
| 1100 | + error(Eshortread); | |
| 1101 | + n = cl->nreaddata; | |
| 1102 | + memmove(a, cl->readdata, cl->nreaddata); | |
| 1103 | + free(cl->readdata); | |
| 1104 | + cl->readdata = nil; | |
| 1105 | + break; | |
| 1106 | + | |
| 1107 | + case Qrefresh: | |
| 1108 | + if(n < 5*4) | |
| 1109 | + error(Ebadarg); | |
| 1110 | + for(;;){ | |
| 1111 | + if(cl->refreshme || cl->refresh) | |
| 1112 | + break; | |
| 1113 | + qunlock(&sdraw.lk); | |
| 1114 | + if(waserror()){ | |
| 1115 | + qlock(&sdraw.lk); /* restore lock for waserror() above */ | |
| 1116 | + nexterror(); | |
| 1117 | + } | |
| 1118 | + sleep(&cl->refrend, drawrefactive, cl); | |
| 1119 | + poperror(); | |
| 1120 | + qlock(&sdraw.lk); | |
| 1121 | + } | |
| 1122 | + p = a; | |
| 1123 | + while(cl->refresh && n>=5*4){ | |
| 1124 | + r = cl->refresh; | |
| 1125 | + BPLONG(p+0*4, r->dimage->id); | |
| 1126 | + BPLONG(p+1*4, r->r.min.x); | |
| 1127 | + BPLONG(p+2*4, r->r.min.y); | |
| 1128 | + BPLONG(p+3*4, r->r.max.x); | |
| 1129 | + BPLONG(p+4*4, r->r.max.y); | |
| 1130 | + cl->refresh = r->next; | |
| 1131 | + free(r); | |
| 1132 | + p += 5*4; | |
| 1133 | + n -= 5*4; | |
| 1134 | + } | |
| 1135 | + cl->refreshme = 0; | |
| 1136 | + n = p-(uchar*)a; | |
| 1137 | + } | |
| 1138 | + qunlock(&sdraw.lk); | |
| 1139 | + poperror(); | |
| 1140 | + return n; | |
| 1141 | +} | |
| 1142 | + | |
| 1143 | +void | |
| 1144 | +drawwakeall(void) | |
| 1145 | +{ | |
| 1146 | + Client *cl; | |
| 1147 | + int i; | |
| 1148 | + | |
| 1149 | + for(i=0; i<sdraw.nclient; i++){ | |
| 1150 | + cl = sdraw.client[i]; | |
| 1151 | + if(cl && (cl->refreshme || cl->refresh)) | |
| 1152 | + wakeup(&cl->refrend); | |
| 1153 | + } | |
| 1154 | +} | |
| 1155 | + | |
| 1156 | +static long | |
| 1157 | +drawwrite(Chan *c, void *a, long n, vlong offset) | |
| 1158 | +{ | |
| 1159 | + char buf[128], *fields[4], *q; | |
| 1160 | + Client *cl; | |
| 1161 | + int i, m, red, green, blue, x; | |
| 1162 | + | |
| 1163 | + USED(offset); | |
| 1164 | + | |
| 1165 | + if(c->qid.type & QTDIR) | |
| 1166 | + error(Eisdir); | |
| 1167 | + cl = drawclient(c); | |
| 1168 | + qlock(&sdraw.lk); | |
| 1169 | + if(waserror()){ | |
| 1170 | + drawwakeall(); | |
| 1171 | + qunlock(&sdraw.lk); | |
| 1172 | + nexterror(); | |
| 1173 | + } | |
| 1174 | + switch(QID(c->qid)){ | |
| 1175 | + case Qctl: | |
| 1176 | + if(n != 4) | |
| 1177 | + error("unknown draw control request"); | |
| 1178 | + cl->infoid = BGLONG((uchar*)a); | |
| 1179 | + break; | |
| 1180 | + | |
| 1181 | + case Qcolormap: | |
| 1182 | + drawactive(1); /* to restore map from backup */ | |
| 1183 | + m = n; | |
| 1184 | + n = 0; | |
| 1185 | + while(m > 0){ | |
| 1186 | + x = m; | |
| 1187 | + if(x > sizeof(buf)-1) | |
| 1188 | + x = sizeof(buf)-1; | |
| 1189 | + q = memccpy(buf, a, '\n', x); | |
| 1190 | + if(q == 0) | |
| 1191 | + break; | |
| 1192 | + i = q-buf; | |
| 1193 | + n += i; | |
| 1194 | + a = (char*)a + i; | |
| 1195 | + m -= i; | |
| 1196 | + *q = 0; | |
| 1197 | + if(tokenize(buf, fields, nelem(fields)) != 4) | |
| 1198 | + error(Ebadarg); | |
| 1199 | + i = strtoul(fields[0], 0, 0); | |
| 1200 | + red = strtoul(fields[1], 0, 0); | |
| 1201 | + green = strtoul(fields[2], 0, 0); | |
| 1202 | + blue = strtoul(fields[3], &q, 0); | |
| 1203 | + if(fields[3] == q) | |
| 1204 | + error(Ebadarg); | |
| 1205 | + if(red>255 || green>255 || blue>255 || i<0 || i>255) | |
| 1206 | + error(Ebadarg); | |
| 1207 | + red |= red<<8; | |
| 1208 | + red |= red<<16; | |
| 1209 | + green |= green<<8; | |
| 1210 | + green |= green<<16; | |
| 1211 | + blue |= blue<<8; | |
| 1212 | + blue |= blue<<16; | |
| 1213 | + setcolor(i, red, green, blue); | |
| 1214 | + } | |
| 1215 | + break; | |
| 1216 | + | |
| 1217 | + case Qdata: | |
| 1218 | + drawmesg(cl, a, n); | |
| 1219 | + drawwakeall(); | |
| 1220 | + break; | |
| 1221 | + | |
| 1222 | + default: | |
| 1223 | + error(Ebadusefd); | |
| 1224 | + } | |
| 1225 | + qunlock(&sdraw.lk); | |
| 1226 | + poperror(); | |
| 1227 | + return n; | |
| 1228 | +} | |
| 1229 | + | |
| 1230 | +uchar* | |
| 1231 | +drawcoord(uchar *p, uchar *maxp, int oldx, int *newx) | |
| 1232 | +{ | |
| 1233 | + int b, x; | |
| 1234 | + | |
| 1235 | + if(p >= maxp) | |
| 1236 | + error(Eshortdraw); | |
| 1237 | + b = *p++; | |
| 1238 | + x = b & 0x7F; | |
| 1239 | + if(b & 0x80){ | |
| 1240 | + if(p+1 >= maxp) | |
| 1241 | + error(Eshortdraw); | |
| 1242 | + x |= *p++ << 7; | |
| 1243 | + x |= *p++ << 15; | |
| 1244 | + if(x & (1<<22)) | |
| 1245 | + x |= ~0<<23; | |
| 1246 | + }else{ | |
| 1247 | + if(b & 0x40) | |
| 1248 | + x |= ~0<<7; | |
| 1249 | + x += oldx; | |
| 1250 | + } | |
| 1251 | + *newx = x; | |
| 1252 | + return p; | |
| 1253 | +} | |
| 1254 | + | |
| 1255 | +static void | |
| 1256 | +printmesg(char *fmt, uchar *a, int plsprnt) | |
| 1257 | +{ | |
| 1258 | + char buf[256]; | |
| 1259 | + char *p, *q; | |
| 1260 | + int s; | |
| 1261 | + | |
| 1262 | + if(1|| plsprnt==0){ | |
| 1263 | + SET(s); | |
| 1264 | + SET(q); | |
| 1265 | + SET(p); | |
| 1266 | + USED(fmt); | |
| 1267 | + USED(a); | |
| 1268 | + USED(buf); | |
| 1269 | + USED(p); | |
| 1270 | + USED(q); | |
| 1271 | + USED(s); | |
| 1272 | + return; | |
| 1273 | + } | |
| 1274 | + q = buf; | |
| 1275 | + *q++ = *a++; | |
| 1276 | + for(p=fmt; *p; p++){ | |
| 1277 | + switch(*p){ | |
| 1278 | + case 'l': | |
| 1279 | + q += sprint(q, " %ld", (long)BGLONG(a)); | |
| 1280 | + a += 4; | |
| 1281 | + break; | |
| 1282 | + case 'L': | |
| 1283 | + q += sprint(q, " %.8lux", (ulong)BGLONG(a)); | |
| 1284 | + a += 4; | |
| 1285 | + break; | |
| 1286 | + case 'R': | |
| 1287 | + q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12)); | |
| 1288 | + a += 16; | |
| 1289 | + break; | |
| 1290 | + case 'P': | |
| 1291 | + q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4)); | |
| 1292 | + a += 8; | |
| 1293 | + break; | |
| 1294 | + case 'b': | |
| 1295 | + q += sprint(q, " %d", *a++); | |
| 1296 | + break; | |
| 1297 | + case 's': | |
| 1298 | + q += sprint(q, " %d", BGSHORT(a)); | |
| 1299 | + a += 2; | |
| 1300 | + break; | |
| 1301 | + case 'S': | |
| 1302 | + q += sprint(q, " %.4ux", BGSHORT(a)); | |
| 1303 | + a += 2; | |
| 1304 | + break; | |
| 1305 | + } | |
| 1306 | + } | |
| 1307 | + *q++ = '\n'; | |
| 1308 | + *q = 0; | |
| 1309 | + iprint("%.*s", (int)(q-buf), buf); | |
| 1310 | +} | |
| 1311 | + | |
| 1312 | +void | |
| 1313 | +drawmesg(Client *client, void *av, int n) | |
| 1314 | +{ | |
| 1315 | + int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush; | |
| 1316 | + uchar *u, *a, refresh; | |
| 1317 | + char *fmt; | |
| 1318 | + ulong value, chan; | |
| 1319 | + Rectangle r, clipr; | |
| 1320 | + Point p, q, *pp, sp; | |
| 1321 | + Memimage *i, *dst, *src, *mask; | |
| 1322 | + Memimage *l, **lp; | |
| 1323 | + Memscreen *scrn; | |
| 1324 | + DImage *font, *ll, *di, *ddst, *dsrc; | |
| 1325 | + DName *dn; | |
| 1326 | + DScreen *dscrn; | |
| 1327 | + FChar *fc; | |
| 1328 | + Refx *refx; | |
| 1329 | + CScreen *cs; | |
| 1330 | + Refreshfn reffn; | |
| 1331 | + | |
| 1332 | + a = av; | |
| 1333 | + m = 0; | |
| 1334 | + fmt = nil; | |
| 1335 | + if(waserror()){ | |
| 1336 | + if(fmt) printmesg(fmt, a, 1); | |
| 1337 | + /* iprint("error: %s\n", up->errstr); */ | |
| 1338 | + nexterror(); | |
| 1339 | + } | |
| 1340 | + while((n-=m) > 0){ | |
| 1341 | + USED(fmt); | |
| 1342 | + a += m; | |
| 1343 | + switch(*a){ | |
| 1344 | + default: | |
| 1345 | + error("bad draw command"); | |
| 1346 | + /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */ | |
| 1347 | + case 'b': | |
| 1348 | + printmesg(fmt="LLbLbRRL", a, 0); | |
| 1349 | + m = 1+4+4+1+4+1+4*4+4*4+4; | |
| 1350 | + if(n < m) | |
| 1351 | + error(Eshortdraw); | |
| 1352 | + dstid = BGLONG(a+1); | |
| 1353 | + scrnid = BGSHORT(a+5); | |
| 1354 | + refresh = a[9]; | |
| 1355 | + chan = BGLONG(a+10); | |
| 1356 | + repl = a[14]; | |
| 1357 | + drawrectangle(&r, a+15); | |
| 1358 | + drawrectangle(&clipr, a+31); | |
| 1359 | + value = BGLONG(a+47); | |
| 1360 | + if(drawlookup(client, dstid, 0)) | |
| 1361 | + error(Eimageexists); | |
| 1362 | + if(scrnid){ | |
| 1363 | + dscrn = drawlookupscreen(client, scrnid, &cs); | |
| 1364 | + scrn = dscrn->screen; | |
| 1365 | + if(repl || chan!=scrn->image->chan) | |
| 1366 | + error("image parameters incompatible with screen"); | |
| 1367 | + reffn = nil; | |
| 1368 | + switch(refresh){ | |
| 1369 | + case Refbackup: | |
| 1370 | + break; | |
| 1371 | + case Refnone: | |
| 1372 | + reffn = memlnorefresh; | |
| 1373 | + break; | |
| 1374 | + case Refmesg: | |
| 1375 | + reffn = drawrefresh; | |
| 1376 | + break; | |
| 1377 | + default: | |
| 1378 | + error("unknown refresh method"); | |
| 1379 | + } | |
| 1380 | + l = memlalloc(scrn, r, reffn, 0, value); | |
| 1381 | + if(l == 0) | |
| 1382 | + error(Edrawmem); | |
| 1383 | + addflush(l->layer->screenr); | |
| 1384 | + l->clipr = clipr; | |
| 1385 | + rectclip(&l->clipr, r); | |
| 1386 | + if(drawinstall(client, dstid, l, dscrn) == 0){ | |
| 1387 | + memldelete(l); | |
| 1388 | + error(Edrawmem); | |
| 1389 | + } | |
| 1390 | + dscrn->ref++; | |
| 1391 | + if(reffn){ | |
| 1392 | + refx = nil; | |
| 1393 | + if(reffn == drawrefresh){ | |
| 1394 | + refx = malloc(sizeof(Refx)); | |
| 1395 | + if(refx == 0){ | |
| 1396 | + drawuninstall(client, dstid); | |
| 1397 | + error(Edrawmem); | |
| 1398 | + } | |
| 1399 | + refx->client = client; | |
| 1400 | + refx->dimage = drawlookup(client, dstid, 1); | |
| 1401 | + } | |
| 1402 | + memlsetrefresh(l, reffn, refx); | |
| 1403 | + } | |
| 1404 | + continue; | |
| 1405 | + } | |
| 1406 | + i = allocmemimage(r, chan); | |
| 1407 | + if(i == 0) | |
| 1408 | + error(Edrawmem); | |
| 1409 | + if(repl) | |
| 1410 | + i->flags |= Frepl; | |
| 1411 | + i->clipr = clipr; | |
| 1412 | + if(!repl) | |
| 1413 | + rectclip(&i->clipr, r); | |
| 1414 | + if(drawinstall(client, dstid, i, 0) == 0){ | |
| 1415 | + freememimage(i); | |
| 1416 | + error(Edrawmem); | |
| 1417 | + } | |
| 1418 | + memfillcolor(i, value); | |
| 1419 | + continue; | |
| 1420 | + | |
| 1421 | + /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */ | |
| 1422 | + case 'A': | |
| 1423 | + printmesg(fmt="LLLb", a, 1); | |
| 1424 | + m = 1+4+4+4+1; | |
| 1425 | + if(n < m) | |
| 1426 | + error(Eshortdraw); | |
| 1427 | + dstid = BGLONG(a+1); | |
| 1428 | + if(dstid == 0) | |
| 1429 | + error(Ebadarg); | |
| 1430 | + if(drawlookupdscreen(dstid)) | |
| 1431 | + error(Escreenexists); | |
| 1432 | + ddst = drawlookup(client, BGLONG(a+5), 1); | |
| 1433 | + dsrc = drawlookup(client, BGLONG(a+9), 1); | |
| 1434 | + if(ddst==0 || dsrc==0) | |
| 1435 | + error(Enodrawimage); | |
| 1436 | + if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0) | |
| 1437 | + error(Edrawmem); | |
| 1438 | + continue; | |
| 1439 | + | |
| 1440 | + /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */ | |
| 1441 | + case 'c': | |
| 1442 | + printmesg(fmt="LbR", a, 0); | |
| 1443 | + m = 1+4+1+4*4; | |
| 1444 | + if(n < m) | |
| 1445 | + error(Eshortdraw); | |
| 1446 | + ddst = drawlookup(client, BGLONG(a+1), 1); | |
| 1447 | + if(ddst == nil) | |
| 1448 | + error(Enodrawimage); | |
| 1449 | + if(ddst->name) | |
| 1450 | + error("can't change repl/clipr of shared image"); | |
| 1451 | + dst = ddst->image; | |
| 1452 | + if(a[5]) | |
| 1453 | + dst->flags |= Frepl; | |
| 1454 | + drawrectangle(&dst->clipr, a+6); | |
| 1455 | + continue; | |
| 1456 | + | |
| 1457 | + /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */ | |
| 1458 | + case 'd': | |
| 1459 | + printmesg(fmt="LLLRPP", a, 0); | |
| 1460 | + m = 1+4+4+4+4*4+2*4+2*4; | |
| 1461 | + if(n < m) | |
| 1462 | + error(Eshortdraw); | |
| 1463 | + dst = drawimage(client, a+1); | |
| 1464 | + dstid = BGLONG(a+1); | |
| 1465 | + src = drawimage(client, a+5); | |
| 1466 | + mask = drawimage(client, a+9); | |
| 1467 | + drawrectangle(&r, a+13); | |
| 1468 | + drawpoint(&p, a+29); | |
| 1469 | + drawpoint(&q, a+37); | |
| 1470 | + op = drawclientop(client); | |
| 1471 | + memdraw(dst, r, src, p, mask, q, op); | |
| 1472 | + dstflush(dstid, dst, r); | |
| 1473 | + continue; | |
| 1474 | + | |
| 1475 | + /* toggle debugging: 'D' val[1] */ | |
| 1476 | + case 'D': | |
| 1477 | + printmesg(fmt="b", a, 0); | |
| 1478 | + m = 1+1; | |
| 1479 | + if(n < m) | |
| 1480 | + error(Eshortdraw); | |
| 1481 | + drawdebug = a[1]; | |
| 1482 | + continue; | |
| 1483 | + | |
| 1484 | + /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/ | |
| 1485 | + case 'e': | |
| 1486 | + case 'E': | |
| 1487 | + printmesg(fmt="LLPlllPll", a, 0); | |
| 1488 | + m = 1+4+4+2*4+4+4+4+2*4+2*4; | |
| 1489 | + if(n < m) | |
| 1490 | + error(Eshortdraw); | |
| 1491 | + dst = drawimage(client, a+1); | |
| 1492 | + dstid = BGLONG(a+1); | |
| 1493 | + src = drawimage(client, a+5); | |
| 1494 | + drawpoint(&p, a+9); | |
| 1495 | + e0 = BGLONG(a+17); | |
| 1496 | + e1 = BGLONG(a+21); | |
| 1497 | + if(e0<0 || e1<0) | |
| 1498 | + error("invalid ellipse semidiameter"); | |
| 1499 | + j = BGLONG(a+25); | |
| 1500 | + if(j < 0) | |
| 1501 | + error("negative ellipse thickness"); | |
| 1502 | + drawpoint(&sp, a+29); | |
| 1503 | + c = j; | |
| 1504 | + if(*a == 'E') | |
| 1505 | + c = -1; | |
| 1506 | + ox = BGLONG(a+37); | |
| 1507 | + oy = BGLONG(a+41); | |
| 1508 | + op = drawclientop(client); | |
| 1509 | + /* high bit indicates arc angles are present */ | |
| 1510 | + if(ox & (1<<31)){ | |
| 1511 | + if((ox & (1<<30)) == 0) | |
| 1512 | + ox &= ~(1<<31); | |
| 1513 | + memarc(dst, p, e0, e1, c, src, sp, ox, oy, op); | |
| 1514 | + }else | |
| 1515 | + memellipse(dst, p, e0, e1, c, src, sp, op); | |
| 1516 | + dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1)); | |
| 1517 | + continue; | |
| 1518 | + | |
| 1519 | + /* free: 'f' id[4] */ | |
| 1520 | + case 'f': | |
| 1521 | + printmesg(fmt="L", a, 1); | |
| 1522 | + m = 1+4; | |
| 1523 | + if(n < m) | |
| 1524 | + error(Eshortdraw); | |
| 1525 | + ll = drawlookup(client, BGLONG(a+1), 0); | |
| 1526 | + if(ll && ll->dscreen && ll->dscreen->owner != client) | |
| 1527 | + ll->dscreen->owner->refreshme = 1; | |
| 1528 | + drawuninstall(client, BGLONG(a+1)); | |
| 1529 | + continue; | |
| 1530 | + | |
| 1531 | + /* free screen: 'F' id[4] */ | |
| 1532 | + case 'F': | |
| 1533 | + printmesg(fmt="L", a, 1); | |
| 1534 | + m = 1+4; | |
| 1535 | + if(n < m) | |
| 1536 | + error(Eshortdraw); | |
| 1537 | + drawlookupscreen(client, BGLONG(a+1), &cs); | |
| 1538 | + drawuninstallscreen(client, cs); | |
| 1539 | + continue; | |
| 1540 | + | |
| 1541 | + /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */ | |
| 1542 | + case 'i': | |
| 1543 | + printmesg(fmt="Llb", a, 1); | |
| 1544 | + m = 1+4+4+1; | |
| 1545 | + if(n < m) | |
| 1546 | + error(Eshortdraw); | |
| 1547 | + dstid = BGLONG(a+1); | |
| 1548 | + if(dstid == 0) | |
| 1549 | + error("can't use display as font"); | |
| 1550 | + font = drawlookup(client, dstid, 1); | |
| 1551 | + if(font == 0) | |
| 1552 | + error(Enodrawimage); | |
| 1553 | + if(font->image->layer) | |
| 1554 | + error("can't use window as font"); | |
| 1555 | + ni = BGLONG(a+5); | |
| 1556 | + if(ni<=0 || ni>4096) | |
| 1557 | + error("bad font size (4096 chars max)"); | |
| 1558 | + free(font->fchar); /* should we complain if non-zero? */ | |
| 1559 | + font->fchar = malloc(ni*sizeof(FChar)); | |
| 1560 | + if(font->fchar == 0) | |
| 1561 | + error("no memory for font"); | |
| 1562 | + memset(font->fchar, 0, ni*sizeof(FChar)); | |
| 1563 | + font->nfchar = ni; | |
| 1564 | + font->ascent = a[9]; | |
| 1565 | + continue; | |
| 1566 | + | |
| 1567 | + /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */ | |
| 1568 | + case 'l': | |
| 1569 | + printmesg(fmt="LLSRPbb", a, 0); | |
| 1570 | + m = 1+4+4+2+4*4+2*4+1+1; | |
| 1571 | + if(n < m) | |
| 1572 | + error(Eshortdraw); | |
| 1573 | + font = drawlookup(client, BGLONG(a+1), 1); | |
| 1574 | + if(font == 0) | |
| 1575 | + error(Enodrawimage); | |
| 1576 | + if(font->nfchar == 0) | |
| 1577 | + error(Enotfont); | |
| 1578 | + src = drawimage(client, a+5); | |
| 1579 | + ci = BGSHORT(a+9); | |
| 1580 | + if(ci >= font->nfchar) | |
| 1581 | + error(Eindex); | |
| 1582 | + drawrectangle(&r, a+11); | |
| 1583 | + drawpoint(&p, a+27); | |
| 1584 | + memdraw(font->image, r, src, p, memopaque, p, S); | |
| 1585 | + fc = &font->fchar[ci]; | |
| 1586 | + fc->minx = r.min.x; | |
| 1587 | + fc->maxx = r.max.x; | |
| 1588 | + fc->miny = r.min.y; | |
| 1589 | + fc->maxy = r.max.y; | |
| 1590 | + fc->left = a[35]; | |
| 1591 | + fc->width = a[36]; | |
| 1592 | + continue; | |
| 1593 | + | |
| 1594 | + /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */ | |
| 1595 | + case 'L': | |
| 1596 | + printmesg(fmt="LPPlllLP", a, 0); | |
| 1597 | + m = 1+4+2*4+2*4+4+4+4+4+2*4; | |
| 1598 | + if(n < m) | |
| 1599 | + error(Eshortdraw); | |
| 1600 | + dst = drawimage(client, a+1); | |
| 1601 | + dstid = BGLONG(a+1); | |
| 1602 | + drawpoint(&p, a+5); | |
| 1603 | + drawpoint(&q, a+13); | |
| 1604 | + e0 = BGLONG(a+21); | |
| 1605 | + e1 = BGLONG(a+25); | |
| 1606 | + j = BGLONG(a+29); | |
| 1607 | + if(j < 0) | |
| 1608 | + error("negative line width"); | |
| 1609 | + src = drawimage(client, a+33); | |
| 1610 | + drawpoint(&sp, a+37); | |
| 1611 | + op = drawclientop(client); | |
| 1612 | + memline(dst, p, q, e0, e1, j, src, sp, op); | |
| 1613 | + /* avoid memlinebbox if possible */ | |
| 1614 | + if(dstid==0 || dst->layer!=nil){ | |
| 1615 | + /* BUG: this is terribly inefficient: update maximal containing rect*/ | |
| 1616 | + r = memlinebbox(p, q, e0, e1, j); | |
| 1617 | + dstflush(dstid, dst, insetrect(r, -(1+1+j))); | |
| 1618 | + } | |
| 1619 | + continue; | |
| 1620 | + | |
| 1621 | + /* create image mask: 'm' newid[4] id[4] */ | |
| 1622 | +/* | |
| 1623 | + * | |
| 1624 | + case 'm': | |
| 1625 | + printmesg("LL", a, 0); | |
| 1626 | + m = 4+4; | |
| 1627 | + if(n < m) | |
| 1628 | + error(Eshortdraw); | |
| 1629 | + break; | |
| 1630 | + * | |
| 1631 | + */ | |
| 1632 | + | |
| 1633 | + /* attach to a named image: 'n' dstid[4] j[1] name[j] */ | |
| 1634 | + case 'n': | |
| 1635 | + printmesg(fmt="Lz", a, 0); | |
| 1636 | + m = 1+4+1; | |
| 1637 | + if(n < m) | |
| 1638 | + error(Eshortdraw); | |
| 1639 | + j = a[5]; | |
| 1640 | + if(j == 0) /* give me a non-empty name please */ | |
| 1641 | + error(Eshortdraw); | |
| 1642 | + m += j; | |
| 1643 | + if(n < m) | |
| 1644 | + error(Eshortdraw); | |
| 1645 | + dstid = BGLONG(a+1); | |
| 1646 | + if(drawlookup(client, dstid, 0)) | |
| 1647 | + error(Eimageexists); | |
| 1648 | + dn = drawlookupname(j, (char*)a+6); | |
| 1649 | + if(dn == nil) | |
| 1650 | + error(Enoname); | |
| 1651 | + if(drawinstall(client, dstid, dn->dimage->image, 0) == 0) | |
| 1652 | + error(Edrawmem); | |
| 1653 | + di = drawlookup(client, dstid, 0); | |
| 1654 | + if(di == 0) | |
| 1655 | + error("draw: can't happen"); | |
| 1656 | + di->vers = dn->vers; | |
| 1657 | + di->name = smalloc(j+1); | |
| 1658 | + di->fromname = dn->dimage; | |
| 1659 | + di->fromname->ref++; | |
| 1660 | + memmove(di->name, a+6, j); | |
| 1661 | + di->name[j] = 0; | |
| 1662 | + client->infoid = dstid; | |
| 1663 | + continue; | |
| 1664 | + | |
| 1665 | + /* name an image: 'N' dstid[4] in[1] j[1] name[j] */ | |
| 1666 | + case 'N': | |
| 1667 | + printmesg(fmt="Lbz", a, 0); | |
| 1668 | + m = 1+4+1+1; | |
| 1669 | + if(n < m) | |
| 1670 | + error(Eshortdraw); | |
| 1671 | + c = a[5]; | |
| 1672 | + j = a[6]; | |
| 1673 | + if(j == 0) /* give me a non-empty name please */ | |
| 1674 | + error(Eshortdraw); | |
| 1675 | + m += j; | |
| 1676 | + if(n < m) | |
| 1677 | + error(Eshortdraw); | |
| 1678 | + di = drawlookup(client, BGLONG(a+1), 0); | |
| 1679 | + if(di == 0) | |
| 1680 | + error(Enodrawimage); | |
| 1681 | + if(di->name) | |
| 1682 | + error(Enamed); | |
| 1683 | + if(c) | |
| 1684 | + drawaddname(client, di, j, (char*)a+7); | |
| 1685 | + else{ | |
| 1686 | + dn = drawlookupname(j, (char*)a+7); | |
| 1687 | + if(dn == nil) | |
| 1688 | + error(Enoname); | |
| 1689 | + if(dn->dimage != di) | |
| 1690 | + error(Ewrongname); | |
| 1691 | + drawdelname(dn); | |
| 1692 | + } | |
| 1693 | + continue; | |
| 1694 | + | |
| 1695 | + /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */ | |
| 1696 | + case 'o': | |
| 1697 | + printmesg(fmt="LPP", a, 0); | |
| 1698 | + m = 1+4+2*4+2*4; | |
| 1699 | + if(n < m) | |
| 1700 | + error(Eshortdraw); | |
| 1701 | + dst = drawimage(client, a+1); | |
| 1702 | + if(dst->layer){ | |
| 1703 | + drawpoint(&p, a+5); | |
| 1704 | + drawpoint(&q, a+13); | |
| 1705 | + r = dst->layer->screenr; | |
| 1706 | + ni = memlorigin(dst, p, q); | |
| 1707 | + if(ni < 0) | |
| 1708 | + error("image origin failed"); | |
| 1709 | + if(ni > 0){ | |
| 1710 | + addflush(r); | |
| 1711 | + addflush(dst->layer->screenr); | |
| 1712 | + ll = drawlookup(client, BGLONG(a+1), 1); | |
| 1713 | + drawrefreshscreen(ll, client); | |
| 1714 | + } | |
| 1715 | + } | |
| 1716 | + continue; | |
| 1717 | + | |
| 1718 | + /* set compositing operator for next draw operation: 'O' op */ | |
| 1719 | + case 'O': | |
| 1720 | + printmesg(fmt="b", a, 0); | |
| 1721 | + m = 1+1; | |
| 1722 | + if(n < m) | |
| 1723 | + error(Eshortdraw); | |
| 1724 | + client->op = a[1]; | |
| 1725 | + continue; | |
| 1726 | + | |
| 1727 | + /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ | |
| 1728 | + /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */ | |
| 1729 | + case 'p': | |
| 1730 | + case 'P': | |
| 1731 | + printmesg(fmt="LslllLPP", a, 0); | |
| 1732 | + m = 1+4+2+4+4+4+4+2*4; | |
| 1733 | + if(n < m) | |
| 1734 | + error(Eshortdraw); | |
| 1735 | + dstid = BGLONG(a+1); | |
| 1736 | + dst = drawimage(client, a+1); | |
| 1737 | + ni = BGSHORT(a+5); | |
| 1738 | + if(ni < 0) | |
| 1739 | + error("negative count in polygon"); | |
| 1740 | + e0 = BGLONG(a+7); | |
| 1741 | + e1 = BGLONG(a+11); | |
| 1742 | + j = 0; | |
| 1743 | + if(*a == 'p'){ | |
| 1744 | + j = BGLONG(a+15); | |
| 1745 | + if(j < 0) | |
| 1746 | + error("negative polygon line width"); | |
| 1747 | + } | |
| 1748 | + src = drawimage(client, a+19); | |
| 1749 | + drawpoint(&sp, a+23); | |
| 1750 | + drawpoint(&p, a+31); | |
| 1751 | + ni++; | |
| 1752 | + pp = malloc(ni*sizeof(Point)); | |
| 1753 | + if(pp == nil) | |
| 1754 | + error(Enomem); | |
| 1755 | + doflush = 0; | |
| 1756 | + if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data)) | |
| 1757 | + doflush = 1; /* simplify test in loop */ | |
| 1758 | + ox = oy = 0; | |
| 1759 | + esize = 0; | |
| 1760 | + u = a+m; | |
| 1761 | + for(y=0; y<ni; y++){ | |
| 1762 | + q = p; | |
| 1763 | + oesize = esize; | |
| 1764 | + u = drawcoord(u, a+n, ox, &p.x); | |
| 1765 | + u = drawcoord(u, a+n, oy, &p.y); | |
| 1766 | + ox = p.x; | |
| 1767 | + oy = p.y; | |
| 1768 | + if(doflush){ | |
| 1769 | + esize = j; | |
| 1770 | + if(*a == 'p'){ | |
| 1771 | + if(y == 0){ | |
| 1772 | + c = memlineendsize(e0); | |
| 1773 | + if(c > esize) | |
| 1774 | + esize = c; | |
| 1775 | + } | |
| 1776 | + if(y == ni-1){ | |
| 1777 | + c = memlineendsize(e1); | |
| 1778 | + if(c > esize) | |
| 1779 | + esize = c; | |
| 1780 | + } | |
| 1781 | + } | |
| 1782 | + if(*a=='P' && e0!=1 && e0 !=~0) | |
| 1783 | + r = dst->clipr; | |
| 1784 | + else if(y > 0){ | |
| 1785 | + r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1); | |
| 1786 | + combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1)); | |
| 1787 | + } | |
| 1788 | + if(rectclip(&r, dst->clipr)) /* should perhaps be an arg to dstflush */ | |
| 1789 | + dstflush(dstid, dst, r); | |
| 1790 | + } | |
| 1791 | + pp[y] = p; | |
| 1792 | + } | |
| 1793 | + if(y == 1) | |
| 1794 | + dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1)); | |
| 1795 | + op = drawclientop(client); | |
| 1796 | + if(*a == 'p') | |
| 1797 | + mempoly(dst, pp, ni, e0, e1, j, src, sp, op); | |
| 1798 | + else | |
| 1799 | + memfillpoly(dst, pp, ni, e0, src, sp, op); | |
| 1800 | + free(pp); | |
| 1801 | + m = u-a; | |
| 1802 | + continue; | |
| 1803 | + | |
| 1804 | + /* read: 'r' id[4] R[4*4] */ | |
| 1805 | + case 'r': | |
| 1806 | + printmesg(fmt="LR", a, 0); | |
| 1807 | + m = 1+4+4*4; | |
| 1808 | + if(n < m) | |
| 1809 | + error(Eshortdraw); | |
| 1810 | + i = drawimage(client, a+1); | |
| 1811 | + drawrectangle(&r, a+5); | |
| 1812 | + if(!rectinrect(r, i->r)) | |
| 1813 | + error(Ereadoutside); | |
| 1814 | + c = bytesperline(r, i->depth); | |
| 1815 | + c *= Dy(r); | |
| 1816 | + free(client->readdata); | |
| 1817 | + client->readdata = mallocz(c, 0); | |
| 1818 | + if(client->readdata == nil) | |
| 1819 | + error("readimage malloc failed"); | |
| 1820 | + client->nreaddata = memunload(i, r, client->readdata, c); | |
| 1821 | + if(client->nreaddata < 0){ | |
| 1822 | + free(client->readdata); | |
| 1823 | + client->readdata = nil; | |
| 1824 | + error("bad readimage call"); | |
| 1825 | + } | |
| 1826 | + continue; | |
| 1827 | + | |
| 1828 | + /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */ | |
| 1829 | + /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */ | |
| 1830 | + case 's': | |
| 1831 | + case 'x': | |
| 1832 | + printmesg(fmt="LLLPRPs", a, 0); | |
| 1833 | + m = 1+4+4+4+2*4+4*4+2*4+2; | |
| 1834 | + if(*a == 'x') | |
| 1835 | + m += 4+2*4; | |
| 1836 | + if(n < m) | |
| 1837 | + error(Eshortdraw); | |
| 1838 | + | |
| 1839 | + dst = drawimage(client, a+1); | |
| 1840 | + dstid = BGLONG(a+1); | |
| 1841 | + src = drawimage(client, a+5); | |
| 1842 | + font = drawlookup(client, BGLONG(a+9), 1); | |
| 1843 | + if(font == 0) | |
| 1844 | + error(Enodrawimage); | |
| 1845 | + if(font->nfchar == 0) | |
| 1846 | + error(Enotfont); | |
| 1847 | + drawpoint(&p, a+13); | |
| 1848 | + drawrectangle(&r, a+21); | |
| 1849 | + drawpoint(&sp, a+37); | |
| 1850 | + ni = BGSHORT(a+45); | |
| 1851 | + u = a+m; | |
| 1852 | + m += ni*2; | |
| 1853 | + if(n < m) | |
| 1854 | + error(Eshortdraw); | |
| 1855 | + clipr = dst->clipr; | |
| 1856 | + dst->clipr = r; | |
| 1857 | + op = drawclientop(client); | |
| 1858 | + if(*a == 'x'){ | |
| 1859 | + /* paint background */ | |
| 1860 | + l = drawimage(client, a+47); | |
| 1861 | + drawpoint(&q, a+51); | |
| 1862 | + r.min.x = p.x; | |
| 1863 | + r.min.y = p.y-font->ascent; | |
| 1864 | + r.max.x = p.x; | |
| 1865 | + r.max.y = r.min.y+Dy(font->image->r); | |
| 1866 | + j = ni; | |
| 1867 | + while(--j >= 0){ | |
| 1868 | + ci = BGSHORT(u); | |
| 1869 | + if(ci<0 || ci>=font->nfchar){ | |
| 1870 | + dst->clipr = clipr; | |
| 1871 | + error(Eindex); | |
| 1872 | + } | |
| 1873 | + r.max.x += font->fchar[ci].width; | |
| 1874 | + u += 2; | |
| 1875 | + } | |
| 1876 | + memdraw(dst, r, l, q, memopaque, ZP, op); | |
| 1877 | + u -= 2*ni; | |
| 1878 | + } | |
| 1879 | + q = p; | |
| 1880 | + while(--ni >= 0){ | |
| 1881 | + ci = BGSHORT(u); | |
| 1882 | + if(ci<0 || ci>=font->nfchar){ | |
| 1883 | + dst->clipr = clipr; | |
| 1884 | + error(Eindex); | |
| 1885 | + } | |
| 1886 | + q = drawchar(dst, q, src, &sp, font, ci, op); | |
| 1887 | + u += 2; | |
| 1888 | + } | |
| 1889 | + dst->clipr = clipr; | |
| 1890 | + p.y -= font->ascent; | |
| 1891 | + dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r))); | |
| 1892 | + continue; | |
| 1893 | + | |
| 1894 | + /* use public screen: 'S' id[4] chan[4] */ | |
| 1895 | + case 'S': | |
| 1896 | + printmesg(fmt="Ll", a, 0); | |
| 1897 | + m = 1+4+4; | |
| 1898 | + if(n < m) | |
| 1899 | + error(Eshortdraw); | |
| 1900 | + dstid = BGLONG(a+1); | |
| 1901 | + if(dstid == 0) | |
| 1902 | + error(Ebadarg); | |
| 1903 | + dscrn = drawlookupdscreen(dstid); | |
| 1904 | + if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client)) | |
| 1905 | + error(Enodrawscreen); | |
| 1906 | + if(dscrn->screen->image->chan != BGLONG(a+5)) | |
| 1907 | + error("inconsistent chan"); | |
| 1908 | + if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0) | |
| 1909 | + error(Edrawmem); | |
| 1910 | + continue; | |
| 1911 | + | |
| 1912 | + /* top or bottom windows: 't' top[1] nw[2] n*id[4] */ | |
| 1913 | + case 't': | |
| 1914 | + printmesg(fmt="bsL", a, 0); | |
| 1915 | + m = 1+1+2; | |
| 1916 | + if(n < m) | |
| 1917 | + error(Eshortdraw); | |
| 1918 | + nw = BGSHORT(a+2); | |
| 1919 | + if(nw < 0) | |
| 1920 | + error(Ebadarg); | |
| 1921 | + if(nw == 0) | |
| 1922 | + continue; | |
| 1923 | + m += nw*4; | |
| 1924 | + if(n < m) | |
| 1925 | + error(Eshortdraw); | |
| 1926 | + lp = malloc(nw*sizeof(Memimage*)); | |
| 1927 | + if(lp == 0) | |
| 1928 | + error(Enomem); | |
| 1929 | + if(waserror()){ | |
| 1930 | + free(lp); | |
| 1931 | + nexterror(); | |
| 1932 | + } | |
| 1933 | + for(j=0; j<nw; j++) | |
| 1934 | + lp[j] = drawimage(client, a+1+1+2+j*4); | |
| 1935 | + if(lp[0]->layer == 0) | |
| 1936 | + error("images are not windows"); | |
| 1937 | + for(j=1; j<nw; j++) | |
| 1938 | + if(lp[j]->layer->screen != lp[0]->layer->screen) | |
| 1939 | + error("images not on same screen"); | |
| 1940 | + if(a[1]) | |
| 1941 | + memltofrontn(lp, nw); | |
| 1942 | + else | |
| 1943 | + memltorearn(lp, nw); | |
| 1944 | + if(lp[0]->layer->screen->image->data == screenimage->data) | |
| 1945 | + for(j=0; j<nw; j++) | |
| 1946 | + addflush(lp[j]->layer->screenr); | |
| 1947 | + ll = drawlookup(client, BGLONG(a+1+1+2), 1); | |
| 1948 | + drawrefreshscreen(ll, client); | |
| 1949 | + poperror(); | |
| 1950 | + free(lp); | |
| 1951 | + continue; | |
| 1952 | + | |
| 1953 | + /* visible: 'v' */ | |
| 1954 | + case 'v': | |
| 1955 | + printmesg(fmt="", a, 0); | |
| 1956 | + m = 1; | |
| 1957 | + drawflush(); | |
| 1958 | + continue; | |
| 1959 | + | |
| 1960 | + /* write: 'y' id[4] R[4*4] data[x*1] */ | |
| 1961 | + /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */ | |
| 1962 | + case 'y': | |
| 1963 | + case 'Y': | |
| 1964 | + printmesg(fmt="LR", a, 0); | |
| 1965 | + // iprint("load %c\n", *a); | |
| 1966 | + m = 1+4+4*4; | |
| 1967 | + if(n < m) | |
| 1968 | + error(Eshortdraw); | |
| 1969 | + dstid = BGLONG(a+1); | |
| 1970 | + dst = drawimage(client, a+1); | |
| 1971 | + drawrectangle(&r, a+5); | |
| 1972 | + if(!rectinrect(r, dst->r)) | |
| 1973 | + error(Ewriteoutside); | |
| 1974 | + y = memload(dst, r, a+m, n-m, *a=='Y'); | |
| 1975 | + if(y < 0) | |
| 1976 | + error("bad writeimage call"); | |
| 1977 | + dstflush(dstid, dst, r); | |
| 1978 | + m += y; | |
| 1979 | + continue; | |
| 1980 | + } | |
| 1981 | + } | |
| 1982 | + poperror(); | |
| 1983 | +} | |
| 1984 | + | |
| 1985 | +Dev drawdevtab = { | |
| 1986 | + 'i', | |
| 1987 | + "draw", | |
| 1988 | + | |
| 1989 | + devreset, | |
| 1990 | + devinit, | |
| 1991 | + devshutdown, | |
| 1992 | + drawattach, | |
| 1993 | + drawwalk, | |
| 1994 | + drawstat, | |
| 1995 | + drawopen, | |
| 1996 | + devcreate, | |
| 1997 | + drawclose, | |
| 1998 | + drawread, | |
| 1999 | + devbread, | |
| 2000 | + drawwrite, | |
| 2001 | + devbwrite, | |
| 2002 | + devremove, | |
| 2003 | + devwstat, | |
| 2004 | +}; | |
| 2005 | + | |
| 2006 | +/* | |
| 2007 | + * On 8 bit displays, load the default color map | |
| 2008 | + */ | |
| 2009 | +void | |
| 2010 | +drawcmap(void) | |
| 2011 | +{ | |
| 2012 | + int r, g, b, cr, cg, cb, v; | |
| 2013 | + int num, den; | |
| 2014 | + int i, j; | |
| 2015 | + | |
| 2016 | + drawactive(1); /* to restore map from backup */ | |
| 2017 | + for(r=0,i=0; r!=4; r++) | |
| 2018 | + for(v=0; v!=4; v++,i+=16){ | |
| 2019 | + for(g=0,j=v-r; g!=4; g++) | |
| 2020 | + for(b=0;b!=4;b++,j++){ | |
| 2021 | + den = r; | |
| 2022 | + if(g > den) | |
| 2023 | + den = g; | |
| 2024 | + if(b > den) | |
| 2025 | + den = b; | |
| 2026 | + if(den == 0) /* divide check -- pick grey shades */ | |
| 2027 | + cr = cg = cb = v*17; | |
| 2028 | + else{ | |
| 2029 | + num = 17*(4*den+v); | |
| 2030 | + cr = r*num/den; | |
| 2031 | + cg = g*num/den; | |
| 2032 | + cb = b*num/den; | |
| 2033 | + } | |
| 2034 | + setcolor(i+(j&15), | |
| 2035 | + cr*0x01010101, cg*0x01010101, cb*0x01010101); | |
| 2036 | + } | |
| 2037 | + } | |
| 2038 | +} | |
| 2039 | + | |
| 2040 | +void | |
| 2041 | +drawblankscreen(int blank) | |
| 2042 | +{ | |
| 2043 | + int i, nc; | |
| 2044 | + ulong *p; | |
| 2045 | + | |
| 2046 | + if(blank == sdraw.blanked) | |
| 2047 | + return; | |
| 2048 | + if(!canqlock(&sdraw.lk)) | |
| 2049 | + return; | |
| 2050 | + if(!initscreenimage()){ | |
| 2051 | + qunlock(&sdraw.lk); | |
| 2052 | + return; | |
| 2053 | + } | |
| 2054 | + p = sdraw.savemap; | |
| 2055 | + nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth; | |
| 2056 | + | |
| 2057 | + /* | |
| 2058 | + * blankscreen uses the hardware to blank the screen | |
| 2059 | + * when possible. to help in cases when it is not possible, | |
| 2060 | + * we set the color map to be all black. | |
| 2061 | + */ | |
| 2062 | + if(blank == 0){ /* turn screen on */ | |
| 2063 | + for(i=0; i<nc; i++, p+=3) | |
| 2064 | + setcolor(i, p[0], p[1], p[2]); | |
| 2065 | + // blankscreen(0); | |
| 2066 | + }else{ /* turn screen off */ | |
| 2067 | + // blankscreen(1); | |
| 2068 | + for(i=0; i<nc; i++, p+=3){ | |
| 2069 | + getcolor(i, &p[0], &p[1], &p[2]); | |
| 2070 | + setcolor(i, 0, 0, 0); | |
| 2071 | + } | |
| 2072 | + } | |
| 2073 | + sdraw.blanked = blank; | |
| 2074 | + qunlock(&sdraw.lk); | |
| 2075 | +} | |
| 2076 | + | |
| 2077 | +/* | |
| 2078 | + * record activity on screen, changing blanking as appropriate | |
| 2079 | + */ | |
| 2080 | +void | |
| 2081 | +drawactive(int active) | |
| 2082 | +{ | |
| 2083 | +/* | |
| 2084 | + if(active){ | |
| 2085 | + drawblankscreen(0); | |
| 2086 | + sdraw.blanktime = MACHP(0)->ticks; | |
| 2087 | + }else{ | |
| 2088 | + if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime) | |
| 2089 | + drawblankscreen(1); | |
| 2090 | + } | |
| 2091 | +*/ | |
| 2092 | +} | |
| 2093 | + | |
| 2094 | +int | |
| 2095 | +drawidletime(void) | |
| 2096 | +{ | |
| 2097 | + return 0; | |
| 2098 | +/* return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60; */ | |
| 2099 | +} | |
| 2100 | + | |
| @@ -0,0 +1,638 @@ | ||
| 1 | +#include <sys/types.h> | |
| 2 | +#include <sys/stat.h> | |
| 3 | +#include <dirent.h> | |
| 4 | +#include <fcntl.h> | |
| 5 | +#include <errno.h> | |
| 6 | +#include <stdio.h> /* for remove, rename */ | |
| 7 | +#include <limits.h> | |
| 8 | + | |
| 9 | +#ifndef NAME_MAX | |
| 10 | +# define NAME_MAX 256 | |
| 11 | +#endif | |
| 12 | +#include "u.h" | |
| 13 | +#include "lib.h" | |
| 14 | +#include "dat.h" | |
| 15 | +#include "fns.h" | |
| 16 | +#include "error.h" | |
| 17 | + | |
| 18 | + | |
| 19 | +typedef struct Ufsinfo Ufsinfo; | |
| 20 | + | |
| 21 | +enum | |
| 22 | +{ | |
| 23 | + NUID = 256, | |
| 24 | + NGID = 256, | |
| 25 | + MAXPATH = 1024, | |
| 26 | + MAXCOMP = 128 | |
| 27 | +}; | |
| 28 | + | |
| 29 | +struct Ufsinfo | |
| 30 | +{ | |
| 31 | + int mode; | |
| 32 | + int fd; | |
| 33 | + int uid; | |
| 34 | + int gid; | |
| 35 | + DIR* dir; | |
| 36 | + ulong offset; | |
| 37 | + QLock oq; | |
| 38 | + char nextname[NAME_MAX]; | |
| 39 | +}; | |
| 40 | + | |
| 41 | +char *base = "/"; | |
| 42 | + | |
| 43 | +static Qid fsqid(char*, struct stat *); | |
| 44 | +static void fspath(Chan*, char*, char*); | |
| 45 | +static ulong fsdirread(Chan*, uchar*, int, ulong); | |
| 46 | +static int fsomode(int); | |
| 47 | + | |
| 48 | +/* clumsy hack, but not worse than the Path stuff in the last one */ | |
| 49 | +static char* | |
| 50 | +uc2name(Chan *c) | |
| 51 | +{ | |
| 52 | + char *s; | |
| 53 | + | |
| 54 | + if(c->name == nil) | |
| 55 | + return "/"; | |
| 56 | + s = c2name(c); | |
| 57 | + if(s[0]=='#' && s[1]=='U') | |
| 58 | + return s+2; | |
| 59 | + return s; | |
| 60 | +} | |
| 61 | + | |
| 62 | +static char* | |
| 63 | +lastelem(Chan *c) | |
| 64 | +{ | |
| 65 | + char *s, *t; | |
| 66 | + | |
| 67 | + s = uc2name(c); | |
| 68 | + if((t = strrchr(s, '/')) == nil) | |
| 69 | + return s; | |
| 70 | + if(t[1] == 0) | |
| 71 | + return t; | |
| 72 | + return t+1; | |
| 73 | +} | |
| 74 | + | |
| 75 | +static Chan* | |
| 76 | +fsattach(char *spec) | |
| 77 | +{ | |
| 78 | + Chan *c; | |
| 79 | + struct stat stbuf; | |
| 80 | + static int devno; | |
| 81 | + Ufsinfo *uif; | |
| 82 | + | |
| 83 | + if(stat(base, &stbuf) < 0) | |
| 84 | + error(strerror(errno)); | |
| 85 | + | |
| 86 | + c = devattach('U', spec); | |
| 87 | + | |
| 88 | + uif = mallocz(sizeof(Ufsinfo), 1); | |
| 89 | + uif->mode = stbuf.st_mode; | |
| 90 | + uif->uid = stbuf.st_uid; | |
| 91 | + uif->gid = stbuf.st_gid; | |
| 92 | + | |
| 93 | + c->aux = uif; | |
| 94 | + c->dev = devno++; | |
| 95 | + c->qid.type = QTDIR; | |
| 96 | +/*print("fsattach %s\n", c2name(c));*/ | |
| 97 | + | |
| 98 | + return c; | |
| 99 | +} | |
| 100 | + | |
| 101 | +static Chan* | |
| 102 | +fsclone(Chan *c, Chan *nc) | |
| 103 | +{ | |
| 104 | + Ufsinfo *uif; | |
| 105 | + | |
| 106 | + uif = mallocz(sizeof(Ufsinfo), 1); | |
| 107 | + *uif = *(Ufsinfo*)c->aux; | |
| 108 | + nc->aux = uif; | |
| 109 | + | |
| 110 | + return nc; | |
| 111 | +} | |
| 112 | + | |
| 113 | +static int | |
| 114 | +fswalk1(Chan *c, char *name) | |
| 115 | +{ | |
| 116 | + struct stat stbuf; | |
| 117 | + char path[MAXPATH]; | |
| 118 | + Ufsinfo *uif; | |
| 119 | + | |
| 120 | + fspath(c, name, path); | |
| 121 | + | |
| 122 | + /*print("** fs walk '%s' -> %s\n", path, name); */ | |
| 123 | + | |
| 124 | + if(stat(path, &stbuf) < 0) | |
| 125 | + return 0; | |
| 126 | + | |
| 127 | + uif = c->aux; | |
| 128 | + | |
| 129 | + uif->mode = stbuf.st_mode; | |
| 130 | + uif->uid = stbuf.st_uid; | |
| 131 | + uif->gid = stbuf.st_gid; | |
| 132 | + | |
| 133 | + c->qid = fsqid(path, &stbuf); | |
| 134 | + | |
| 135 | + return 1; | |
| 136 | +} | |
| 137 | + | |
| 138 | +extern Cname* addelem(Cname*, char*); | |
| 139 | + | |
| 140 | +static Walkqid* | |
| 141 | +fswalk(Chan *c, Chan *nc, char **name, int nname) | |
| 142 | +{ | |
| 143 | + int i; | |
| 144 | + Cname *cname; | |
| 145 | + Walkqid *wq; | |
| 146 | + | |
| 147 | + if(nc != nil) | |
| 148 | + panic("fswalk: nc != nil"); | |
| 149 | + wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); | |
| 150 | + nc = devclone(c); | |
| 151 | + cname = c->name; | |
| 152 | + incref(&cname->ref); | |
| 153 | + | |
| 154 | + fsclone(c, nc); | |
| 155 | + wq->clone = nc; | |
| 156 | + for(i=0; i<nname; i++){ | |
| 157 | + nc->name = cname; | |
| 158 | + if(fswalk1(nc, name[i]) == 0) | |
| 159 | + break; | |
| 160 | + cname = addelem(cname, name[i]); | |
| 161 | + wq->qid[i] = nc->qid; | |
| 162 | + } | |
| 163 | + nc->name = nil; | |
| 164 | + cnameclose(cname); | |
| 165 | + if(i != nname){ | |
| 166 | + cclose(nc); | |
| 167 | + wq->clone = nil; | |
| 168 | + } | |
| 169 | + wq->nqid = i; | |
| 170 | + return wq; | |
| 171 | +} | |
| 172 | + | |
| 173 | +static int | |
| 174 | +fsstat(Chan *c, uchar *buf, int n) | |
| 175 | +{ | |
| 176 | + Dir d; | |
| 177 | + struct stat stbuf; | |
| 178 | + char path[MAXPATH]; | |
| 179 | + | |
| 180 | + if(n < BIT16SZ) | |
| 181 | + error(Eshortstat); | |
| 182 | + | |
| 183 | + fspath(c, 0, path); | |
| 184 | + if(stat(path, &stbuf) < 0) | |
| 185 | + error(strerror(errno)); | |
| 186 | + | |
| 187 | + d.name = lastelem(c); | |
| 188 | + d.uid = "unknown"; | |
| 189 | + d.gid = "unknown"; | |
| 190 | + d.muid = "unknown"; | |
| 191 | + d.qid = c->qid; | |
| 192 | + d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777); | |
| 193 | + d.atime = stbuf.st_atime; | |
| 194 | + d.mtime = stbuf.st_mtime; | |
| 195 | + d.length = stbuf.st_size; | |
| 196 | + d.type = 'U'; | |
| 197 | + d.dev = c->dev; | |
| 198 | + return convD2M(&d, buf, n); | |
| 199 | +} | |
| 200 | + | |
| 201 | +static Chan* | |
| 202 | +fsopen(Chan *c, int mode) | |
| 203 | +{ | |
| 204 | + char path[MAXPATH]; | |
| 205 | + int m, isdir; | |
| 206 | + Ufsinfo *uif; | |
| 207 | + | |
| 208 | +/*print("fsopen %s\n", c2name(c));*/ | |
| 209 | + m = mode & (OTRUNC|3); | |
| 210 | + switch(m) { | |
| 211 | + case 0: | |
| 212 | + break; | |
| 213 | + case 1: | |
| 214 | + case 1|16: | |
| 215 | + break; | |
| 216 | + case 2: | |
| 217 | + case 0|16: | |
| 218 | + case 2|16: | |
| 219 | + break; | |
| 220 | + case 3: | |
| 221 | + break; | |
| 222 | + default: | |
| 223 | + error(Ebadarg); | |
| 224 | + } | |
| 225 | + | |
| 226 | + isdir = c->qid.type & QTDIR; | |
| 227 | + | |
| 228 | + if(isdir && mode != OREAD) | |
| 229 | + error(Eperm); | |
| 230 | + | |
| 231 | + m = fsomode(m & 3); | |
| 232 | + c->mode = openmode(mode); | |
| 233 | + | |
| 234 | + uif = c->aux; | |
| 235 | + | |
| 236 | + fspath(c, 0, path); | |
| 237 | + if(isdir) { | |
| 238 | + uif->dir = opendir(path); | |
| 239 | + if(uif->dir == 0) | |
| 240 | + error(strerror(errno)); | |
| 241 | + } | |
| 242 | + else { | |
| 243 | + if(mode & OTRUNC) | |
| 244 | + m |= O_TRUNC; | |
| 245 | + uif->fd = open(path, m, 0666); | |
| 246 | + | |
| 247 | + if(uif->fd < 0) | |
| 248 | + error(strerror(errno)); | |
| 249 | + } | |
| 250 | + uif->offset = 0; | |
| 251 | + | |
| 252 | + c->offset = 0; | |
| 253 | + c->flag |= COPEN; | |
| 254 | + return c; | |
| 255 | +} | |
| 256 | + | |
| 257 | +static void | |
| 258 | +fscreate(Chan *c, char *name, int mode, ulong perm) | |
| 259 | +{ | |
| 260 | + int fd, m; | |
| 261 | + char path[MAXPATH]; | |
| 262 | + struct stat stbuf; | |
| 263 | + Ufsinfo *uif; | |
| 264 | + | |
| 265 | + m = fsomode(mode&3); | |
| 266 | + | |
| 267 | + fspath(c, name, path); | |
| 268 | + | |
| 269 | + uif = c->aux; | |
| 270 | + | |
| 271 | + if(perm & DMDIR) { | |
| 272 | + if(m) | |
| 273 | + error(Eperm); | |
| 274 | + | |
| 275 | + if(mkdir(path, perm & 0777) < 0) | |
| 276 | + error(strerror(errno)); | |
| 277 | + | |
| 278 | + fd = open(path, 0); | |
| 279 | + if(fd >= 0) { | |
| 280 | + chmod(path, perm & 0777); | |
| 281 | + chown(path, uif->uid, uif->uid); | |
| 282 | + } | |
| 283 | + close(fd); | |
| 284 | + | |
| 285 | + uif->dir = opendir(path); | |
| 286 | + if(uif->dir == 0) | |
| 287 | + error(strerror(errno)); | |
| 288 | + } | |
| 289 | + else { | |
| 290 | + fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666); | |
| 291 | + if(fd >= 0) { | |
| 292 | + if(m != 1) { | |
| 293 | + close(fd); | |
| 294 | + fd = open(path, m); | |
| 295 | + } | |
| 296 | + chmod(path, perm & 0777); | |
| 297 | + chown(path, uif->uid, uif->gid); | |
| 298 | + } | |
| 299 | + if(fd < 0) | |
| 300 | + error(strerror(errno)); | |
| 301 | + uif->fd = fd; | |
| 302 | + } | |
| 303 | + | |
| 304 | + if(stat(path, &stbuf) < 0) | |
| 305 | + error(strerror(errno)); | |
| 306 | + c->qid = fsqid(path, &stbuf); | |
| 307 | + c->offset = 0; | |
| 308 | + c->flag |= COPEN; | |
| 309 | + c->mode = openmode(mode); | |
| 310 | +} | |
| 311 | + | |
| 312 | +static void | |
| 313 | +fsclose(Chan *c) | |
| 314 | +{ | |
| 315 | + Ufsinfo *uif; | |
| 316 | + | |
| 317 | + uif = c->aux; | |
| 318 | + | |
| 319 | + if(c->flag & COPEN) { | |
| 320 | + if(c->qid.type & QTDIR) | |
| 321 | + closedir(uif->dir); | |
| 322 | + else | |
| 323 | + close(uif->fd); | |
| 324 | + } | |
| 325 | + | |
| 326 | + free(uif); | |
| 327 | +} | |
| 328 | + | |
| 329 | +static long | |
| 330 | +fsread(Chan *c, void *va, long n, vlong offset) | |
| 331 | +{ | |
| 332 | + int fd, r; | |
| 333 | + Ufsinfo *uif; | |
| 334 | + | |
| 335 | +/*print("fsread %s\n", c2name(c));*/ | |
| 336 | + if(c->qid.type & QTDIR) | |
| 337 | + return fsdirread(c, va, n, offset); | |
| 338 | + | |
| 339 | + uif = c->aux; | |
| 340 | + qlock(&uif->oq); | |
| 341 | + if(waserror()) { | |
| 342 | + qunlock(&uif->oq); | |
| 343 | + nexterror(); | |
| 344 | + } | |
| 345 | + fd = uif->fd; | |
| 346 | + if(uif->offset != offset) { | |
| 347 | + r = lseek(fd, offset, 0); | |
| 348 | + if(r < 0) | |
| 349 | + error(strerror(errno)); | |
| 350 | + uif->offset = offset; | |
| 351 | + } | |
| 352 | + | |
| 353 | + n = read(fd, va, n); | |
| 354 | + if(n < 0) | |
| 355 | + error(strerror(errno)); | |
| 356 | + | |
| 357 | + uif->offset += n; | |
| 358 | + qunlock(&uif->oq); | |
| 359 | + poperror(); | |
| 360 | + | |
| 361 | + return n; | |
| 362 | +} | |
| 363 | + | |
| 364 | +static long | |
| 365 | +fswrite(Chan *c, void *va, long n, vlong offset) | |
| 366 | +{ | |
| 367 | + int fd, r; | |
| 368 | + Ufsinfo *uif; | |
| 369 | + | |
| 370 | + uif = c->aux; | |
| 371 | + | |
| 372 | + qlock(&uif->oq); | |
| 373 | + if(waserror()) { | |
| 374 | + qunlock(&uif->oq); | |
| 375 | + nexterror(); | |
| 376 | + } | |
| 377 | + fd = uif->fd; | |
| 378 | + if(uif->offset != offset) { | |
| 379 | + r = lseek(fd, offset, 0); | |
| 380 | + if(r < 0) | |
| 381 | + error(strerror(errno)); | |
| 382 | + uif->offset = offset; | |
| 383 | + } | |
| 384 | + | |
| 385 | + n = write(fd, va, n); | |
| 386 | + if(n < 0) | |
| 387 | + error(strerror(errno)); | |
| 388 | + | |
| 389 | + uif->offset += n; | |
| 390 | + qunlock(&uif->oq); | |
| 391 | + poperror(); | |
| 392 | + | |
| 393 | + return n; | |
| 394 | +} | |
| 395 | + | |
| 396 | +static void | |
| 397 | +fsremove(Chan *c) | |
| 398 | +{ | |
| 399 | + int n; | |
| 400 | + char path[MAXPATH]; | |
| 401 | + | |
| 402 | + fspath(c, 0, path); | |
| 403 | + if(c->qid.type & QTDIR) | |
| 404 | + n = rmdir(path); | |
| 405 | + else | |
| 406 | + n = remove(path); | |
| 407 | + if(n < 0) | |
| 408 | + error(strerror(errno)); | |
| 409 | +} | |
| 410 | + | |
| 411 | +int | |
| 412 | +fswstat(Chan *c, uchar *buf, int n) | |
| 413 | +{ | |
| 414 | + Dir d; | |
| 415 | + struct stat stbuf; | |
| 416 | + char old[MAXPATH], new[MAXPATH], dir[MAXPATH]; | |
| 417 | + char strs[MAXPATH*3], *p; | |
| 418 | + Ufsinfo *uif; | |
| 419 | + | |
| 420 | + if(convM2D(buf, n, &d, strs) != n) | |
| 421 | + error(Ebadstat); | |
| 422 | + | |
| 423 | + fspath(c, 0, old); | |
| 424 | + if(stat(old, &stbuf) < 0) | |
| 425 | + error(strerror(errno)); | |
| 426 | + | |
| 427 | + uif = c->aux; | |
| 428 | + | |
| 429 | + if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) { | |
| 430 | + fspath(c, 0, old); | |
| 431 | + strcpy(new, old); | |
| 432 | + p = strrchr(new, '/'); | |
| 433 | + strcpy(p+1, d.name); | |
| 434 | + if(rename(old, new) < 0) | |
| 435 | + error(strerror(errno)); | |
| 436 | + } | |
| 437 | + | |
| 438 | + fspath(c, 0, old); | |
| 439 | + if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { | |
| 440 | + if(chmod(old, d.mode&0777) < 0) | |
| 441 | + error(strerror(errno)); | |
| 442 | + uif->mode &= ~0777; | |
| 443 | + uif->mode |= d.mode&0777; | |
| 444 | + } | |
| 445 | +/* | |
| 446 | + p = name2pass(gid, d.gid); | |
| 447 | + if(p == 0) | |
| 448 | + error(Eunknown); | |
| 449 | + | |
| 450 | + if(p->id != stbuf.st_gid) { | |
| 451 | + if(chown(old, stbuf.st_uid, p->id) < 0) | |
| 452 | + error(strerror(errno)); | |
| 453 | + | |
| 454 | + uif->gid = p->id; | |
| 455 | + } | |
| 456 | +*/ | |
| 457 | + return n; | |
| 458 | +} | |
| 459 | + | |
| 460 | +static Qid | |
| 461 | +fsqid(char *p, struct stat *st) | |
| 462 | +{ | |
| 463 | + Qid q; | |
| 464 | + int dev; | |
| 465 | + ulong h; | |
| 466 | + static int nqdev; | |
| 467 | + static uchar *qdev; | |
| 468 | + | |
| 469 | + if(qdev == 0) | |
| 470 | + qdev = mallocz(65536U, 1); | |
| 471 | + | |
| 472 | + q.type = 0; | |
| 473 | + if((st->st_mode&S_IFMT) == S_IFDIR) | |
| 474 | + q.type = QTDIR; | |
| 475 | + | |
| 476 | + dev = st->st_dev & 0xFFFFUL; | |
| 477 | + if(qdev[dev] == 0) | |
| 478 | + qdev[dev] = ++nqdev; | |
| 479 | + | |
| 480 | + h = 0; | |
| 481 | + while(*p != '\0') | |
| 482 | + h += *p++ * 13; | |
| 483 | + | |
| 484 | + q.path = (vlong)qdev[dev]<<32; | |
| 485 | + q.path |= h; | |
| 486 | + q.vers = st->st_mtime; | |
| 487 | + | |
| 488 | + return q; | |
| 489 | +} | |
| 490 | + | |
| 491 | +static void | |
| 492 | +fspath(Chan *c, char *ext, char *path) | |
| 493 | +{ | |
| 494 | + int i, n; | |
| 495 | + char *comp[MAXCOMP]; | |
| 496 | + | |
| 497 | + strcpy(path, base); | |
| 498 | + strcat(path, "/"); | |
| 499 | + strcat(path, uc2name(c)); | |
| 500 | + if(ext){ | |
| 501 | + strcat(path, "/"); | |
| 502 | + strcat(path, ext); | |
| 503 | + } | |
| 504 | + cleanname(path); | |
| 505 | +} | |
| 506 | + | |
| 507 | +static int | |
| 508 | +isdots(char *name) | |
| 509 | +{ | |
| 510 | + if(name[0] != '.') | |
| 511 | + return 0; | |
| 512 | + if(name[1] == '\0') | |
| 513 | + return 1; | |
| 514 | + if(name[1] != '.') | |
| 515 | + return 0; | |
| 516 | + if(name[2] == '\0') | |
| 517 | + return 1; | |
| 518 | + return 0; | |
| 519 | +} | |
| 520 | + | |
| 521 | +static int | |
| 522 | +p9readdir(char *name, Ufsinfo *uif) | |
| 523 | +{ | |
| 524 | + struct dirent *de; | |
| 525 | + | |
| 526 | + if(uif->nextname[0]){ | |
| 527 | + strcpy(name, uif->nextname); | |
| 528 | + uif->nextname[0] = 0; | |
| 529 | + return 1; | |
| 530 | + } | |
| 531 | + | |
| 532 | + de = readdir(uif->dir); | |
| 533 | + if(de == NULL) | |
| 534 | + return 0; | |
| 535 | + | |
| 536 | + strcpy(name, de->d_name); | |
| 537 | + return 1; | |
| 538 | +} | |
| 539 | + | |
| 540 | +static ulong | |
| 541 | +fsdirread(Chan *c, uchar *va, int count, ulong offset) | |
| 542 | +{ | |
| 543 | + int i; | |
| 544 | + Dir d; | |
| 545 | + long n; | |
| 546 | + char de[NAME_MAX]; | |
| 547 | + struct stat stbuf; | |
| 548 | + char path[MAXPATH], dirpath[MAXPATH]; | |
| 549 | + Ufsinfo *uif; | |
| 550 | + | |
| 551 | +/*print("fsdirread %s\n", c2name(c));*/ | |
| 552 | + i = 0; | |
| 553 | + uif = c->aux; | |
| 554 | + | |
| 555 | + errno = 0; | |
| 556 | + if(uif->offset != offset) { | |
| 557 | + if(offset != 0) | |
| 558 | + error("bad offset in fsdirread"); | |
| 559 | + uif->offset = offset; /* sync offset */ | |
| 560 | + uif->nextname[0] = 0; | |
| 561 | + rewinddir(uif->dir); | |
| 562 | + } | |
| 563 | + | |
| 564 | + fspath(c, 0, dirpath); | |
| 565 | + | |
| 566 | + while(i+BIT16SZ < count) { | |
| 567 | + if(!p9readdir(de, uif)) | |
| 568 | + break; | |
| 569 | + | |
| 570 | + if(de[0]==0 || isdots(de)) | |
| 571 | + continue; | |
| 572 | + | |
| 573 | + d.name = de; | |
| 574 | + sprint(path, "%s/%s", dirpath, de); | |
| 575 | + memset(&stbuf, 0, sizeof stbuf); | |
| 576 | + | |
| 577 | + if(stat(path, &stbuf) < 0) { | |
| 578 | + print("dir: bad path %s\n", path); | |
| 579 | + /* but continue... probably a bad symlink */ | |
| 580 | + } | |
| 581 | + | |
| 582 | + d.uid = "unknown"; | |
| 583 | + d.gid = "unknown"; | |
| 584 | + d.qid = fsqid(path, &stbuf); | |
| 585 | + d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777); | |
| 586 | + d.atime = stbuf.st_atime; | |
| 587 | + d.mtime = stbuf.st_mtime; | |
| 588 | + d.length = stbuf.st_size; | |
| 589 | + d.type = 'U'; | |
| 590 | + d.dev = c->dev; | |
| 591 | + n = convD2M(&d, (char*)va+i, count-i); | |
| 592 | + if(n == BIT16SZ){ | |
| 593 | + strcpy(uif->nextname, de); | |
| 594 | + break; | |
| 595 | + } | |
| 596 | + i += n; | |
| 597 | + } | |
| 598 | +/*print("got %d\n", i);*/ | |
| 599 | + uif->offset += i; | |
| 600 | + return i; | |
| 601 | +} | |
| 602 | + | |
| 603 | +static int | |
| 604 | +fsomode(int m) | |
| 605 | +{ | |
| 606 | + switch(m) { | |
| 607 | + case 0: /* OREAD */ | |
| 608 | + case 3: /* OEXEC */ | |
| 609 | + return 0; | |
| 610 | + case 1: /* OWRITE */ | |
| 611 | + return 1; | |
| 612 | + case 2: /* ORDWR */ | |
| 613 | + return 2; | |
| 614 | + } | |
| 615 | + error(Ebadarg); | |
| 616 | + return 0; | |
| 617 | +} | |
| 618 | + | |
| 619 | +Dev fsdevtab = { | |
| 620 | + 'U', | |
| 621 | + "fs", | |
| 622 | + | |
| 623 | + devreset, | |
| 624 | + devinit, | |
| 625 | + devshutdown, | |
| 626 | + fsattach, | |
| 627 | + fswalk, | |
| 628 | + fsstat, | |
| 629 | + fsopen, | |
| 630 | + fscreate, | |
| 631 | + fsclose, | |
| 632 | + fsread, | |
| 633 | + devbread, | |
| 634 | + fswrite, | |
| 635 | + devbwrite, | |
| 636 | + fsremove, | |
| 637 | + fswstat, | |
| 638 | +}; | |
| @@ -0,0 +1,209 @@ | ||
| 1 | +#include <sys/types.h> | |
| 2 | +#include <sys/socket.h> | |
| 3 | +#include <netinet/in.h> | |
| 4 | +#include <netinet/tcp.h> | |
| 5 | +#include <netdb.h> | |
| 6 | + | |
| 7 | +#include "u.h" | |
| 8 | +#include "lib.h" | |
| 9 | +#include "dat.h" | |
| 10 | +#include "fns.h" | |
| 11 | +#include "error.h" | |
| 12 | + | |
| 13 | +#include "devip.h" | |
| 14 | + | |
| 15 | +#undef listen | |
| 16 | +#undef accept | |
| 17 | +#undef bind | |
| 18 | + | |
| 19 | +void | |
| 20 | +osipinit(void) | |
| 21 | +{ | |
| 22 | + char buf[1024]; | |
| 23 | + gethostname(buf, sizeof(buf)); | |
| 24 | + kstrdup(&sysname, buf); | |
| 25 | + | |
| 26 | +} | |
| 27 | + | |
| 28 | +int | |
| 29 | +so_socket(int type) | |
| 30 | +{ | |
| 31 | + int fd, one; | |
| 32 | + | |
| 33 | + switch(type) { | |
| 34 | + default: | |
| 35 | + error("bad protocol type"); | |
| 36 | + case S_TCP: | |
| 37 | + type = SOCK_STREAM; | |
| 38 | + break; | |
| 39 | + case S_UDP: | |
| 40 | + type = SOCK_DGRAM; | |
| 41 | + break; | |
| 42 | + } | |
| 43 | + | |
| 44 | + fd = socket(AF_INET, type, 0); | |
| 45 | + if(fd < 0) | |
| 46 | + oserror(); | |
| 47 | + | |
| 48 | + one = 1; | |
| 49 | + if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){ | |
| 50 | + oserrstr(); | |
| 51 | + print("setsockopt: %r"); | |
| 52 | + } | |
| 53 | + | |
| 54 | + return fd; | |
| 55 | +} | |
| 56 | + | |
| 57 | + | |
| 58 | +void | |
| 59 | +so_connect(int fd, unsigned long raddr, unsigned short rport) | |
| 60 | +{ | |
| 61 | + struct sockaddr_in sin; | |
| 62 | + | |
| 63 | + memset(&sin, 0, sizeof(sin)); | |
| 64 | + sin.sin_family = AF_INET; | |
| 65 | + hnputs(&sin.sin_port, rport); | |
| 66 | + hnputl(&sin.sin_addr.s_addr, raddr); | |
| 67 | + | |
| 68 | + if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) | |
| 69 | + oserror(); | |
| 70 | +} | |
| 71 | + | |
| 72 | +void | |
| 73 | +so_getsockname(int fd, unsigned long *laddr, unsigned short *lport) | |
| 74 | +{ | |
| 75 | + int len; | |
| 76 | + struct sockaddr_in sin; | |
| 77 | + | |
| 78 | + len = sizeof(sin); | |
| 79 | + if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0) | |
| 80 | + oserror(); | |
| 81 | + | |
| 82 | + if(sin.sin_family != AF_INET || len != sizeof(sin)) | |
| 83 | + error("not AF_INET"); | |
| 84 | + | |
| 85 | + *laddr = nhgetl(&sin.sin_addr.s_addr); | |
| 86 | + *lport = nhgets(&sin.sin_port); | |
| 87 | +} | |
| 88 | + | |
| 89 | +void | |
| 90 | +so_listen(int fd) | |
| 91 | +{ | |
| 92 | + if(listen(fd, 5) < 0) | |
| 93 | + oserror(); | |
| 94 | +} | |
| 95 | + | |
| 96 | +int | |
| 97 | +so_accept(int fd, unsigned long *raddr, unsigned short *rport) | |
| 98 | +{ | |
| 99 | + int nfd, len; | |
| 100 | + struct sockaddr_in sin; | |
| 101 | + | |
| 102 | + len = sizeof(sin); | |
| 103 | + nfd = accept(fd, (struct sockaddr*)&sin, &len); | |
| 104 | + if(nfd < 0) | |
| 105 | + oserror(); | |
| 106 | + | |
| 107 | + if(sin.sin_family != AF_INET || len != sizeof(sin)) | |
| 108 | + error("not AF_INET"); | |
| 109 | + | |
| 110 | + *raddr = nhgetl(&sin.sin_addr.s_addr); | |
| 111 | + *rport = nhgets(&sin.sin_port); | |
| 112 | + return nfd; | |
| 113 | +} | |
| 114 | + | |
| 115 | +void | |
| 116 | +so_bind(int fd, int su, unsigned short port) | |
| 117 | +{ | |
| 118 | + int i, one; | |
| 119 | + struct sockaddr_in sin; | |
| 120 | + | |
| 121 | + one = 1; | |
| 122 | + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){ | |
| 123 | + oserrstr(); | |
| 124 | + print("setsockopt: %r"); | |
| 125 | + } | |
| 126 | + | |
| 127 | + if(su) { | |
| 128 | + for(i = 600; i < 1024; i++) { | |
| 129 | + memset(&sin, 0, sizeof(sin)); | |
| 130 | + sin.sin_family = AF_INET; | |
| 131 | + sin.sin_port = i; | |
| 132 | + | |
| 133 | + if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0) | |
| 134 | + return; | |
| 135 | + } | |
| 136 | + oserror(); | |
| 137 | + } | |
| 138 | + | |
| 139 | + memset(&sin, 0, sizeof(sin)); | |
| 140 | + sin.sin_family = AF_INET; | |
| 141 | + hnputs(&sin.sin_port, port); | |
| 142 | + | |
| 143 | + if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) | |
| 144 | + oserror(); | |
| 145 | +} | |
| 146 | + | |
| 147 | +int | |
| 148 | +so_gethostbyname(char *host, char**hostv, int n) | |
| 149 | +{ | |
| 150 | + int i; | |
| 151 | + char buf[32]; | |
| 152 | + unsigned char *p; | |
| 153 | + struct hostent *hp; | |
| 154 | + | |
| 155 | + hp = gethostbyname(host); | |
| 156 | + if(hp == 0) | |
| 157 | + return 0; | |
| 158 | + | |
| 159 | + for(i = 0; hp->h_addr_list[i] && i < n; i++) { | |
| 160 | + p = (unsigned char*)hp->h_addr_list[i]; | |
| 161 | + sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); | |
| 162 | + hostv[i] = strdup(buf); | |
| 163 | + if(hostv[i] == 0) | |
| 164 | + break; | |
| 165 | + } | |
| 166 | + return i; | |
| 167 | +} | |
| 168 | + | |
| 169 | +char* | |
| 170 | +hostlookup(char *host) | |
| 171 | +{ | |
| 172 | + char buf[100]; | |
| 173 | + uchar *p; | |
| 174 | + struct hostent *he; | |
| 175 | + | |
| 176 | + he = gethostbyname(host); | |
| 177 | + if(he != 0 && he->h_addr_list[0]) { | |
| 178 | + p = (uchar*)he->h_addr_list[0]; | |
| 179 | + sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]); | |
| 180 | + } else | |
| 181 | + strcpy(buf, host); | |
| 182 | + | |
| 183 | + return strdup(buf); | |
| 184 | +} | |
| 185 | + | |
| 186 | +int | |
| 187 | +so_getservbyname(char *service, char *net, char *port) | |
| 188 | +{ | |
| 189 | + struct servent *s; | |
| 190 | + | |
| 191 | + s = getservbyname(service, net); | |
| 192 | + if(s == 0) | |
| 193 | + return -1; | |
| 194 | + | |
| 195 | + sprint(port, "%d", nhgets(&s->s_port)); | |
| 196 | + return 0; | |
| 197 | +} | |
| 198 | + | |
| 199 | +int | |
| 200 | +so_send(int fd, void *d, int n, int f) | |
| 201 | +{ | |
| 202 | + send(fd, d, n, f); | |
| 203 | +} | |
| 204 | + | |
| 205 | +int | |
| 206 | +so_recv(int fd, void *d, int n, int f) | |
| 207 | +{ | |
| 208 | + return recv(fd, d, n, f); | |
| 209 | +} | |
| @@ -0,0 +1,208 @@ | ||
| 1 | +#include <windows.h> | |
| 2 | +#include "winduhz.h" | |
| 3 | +#include "u.h" | |
| 4 | +#include "lib.h" | |
| 5 | +#include "dat.h" | |
| 6 | +#include "fns.h" | |
| 7 | +#include "error.h" | |
| 8 | + | |
| 9 | +#include "devip.h" | |
| 10 | + | |
| 11 | +#pragma comment(lib, "wsock32.lib") | |
| 12 | + | |
| 13 | +#undef listen | |
| 14 | +#undef accept | |
| 15 | +#undef bind | |
| 16 | + | |
| 17 | +void | |
| 18 | +osipinit(void) | |
| 19 | +{ | |
| 20 | + WSADATA wasdat; | |
| 21 | + char buf[1024]; | |
| 22 | + | |
| 23 | + if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0) | |
| 24 | + panic("no winsock.dll"); | |
| 25 | + | |
| 26 | + gethostname(buf, sizeof(buf)); | |
| 27 | + kstrdup(&sysname, buf); | |
| 28 | +} | |
| 29 | + | |
| 30 | +int | |
| 31 | +so_socket(int type) | |
| 32 | +{ | |
| 33 | + int fd, one; | |
| 34 | + | |
| 35 | + switch(type) { | |
| 36 | + default: | |
| 37 | + error("bad protocol type"); | |
| 38 | + case S_TCP: | |
| 39 | + type = SOCK_STREAM; | |
| 40 | + break; | |
| 41 | + case S_UDP: | |
| 42 | + type = SOCK_DGRAM; | |
| 43 | + break; | |
| 44 | + } | |
| 45 | + | |
| 46 | + fd = socket(AF_INET, type, 0); | |
| 47 | + if(fd < 0) | |
| 48 | + error(sys_errlist[errno]); | |
| 49 | + | |
| 50 | + one = 1; | |
| 51 | + if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0) | |
| 52 | + print("setsockopt: %s", sys_errlist[errno]); | |
| 53 | + | |
| 54 | + | |
| 55 | + return fd; | |
| 56 | +} | |
| 57 | + | |
| 58 | + | |
| 59 | +void | |
| 60 | +so_connect(int fd, unsigned long raddr, unsigned short rport) | |
| 61 | +{ | |
| 62 | + struct sockaddr_in sin; | |
| 63 | + | |
| 64 | + memset(&sin, 0, sizeof(sin)); | |
| 65 | + sin.sin_family = AF_INET; | |
| 66 | + hnputs(&sin.sin_port, rport); | |
| 67 | + hnputl(&sin.sin_addr.s_addr, raddr); | |
| 68 | + | |
| 69 | + if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) | |
| 70 | + error(sys_errlist[errno]); | |
| 71 | +} | |
| 72 | + | |
| 73 | +void | |
| 74 | +so_getsockname(int fd, unsigned long *laddr, unsigned short *lport) | |
| 75 | +{ | |
| 76 | + int len; | |
| 77 | + struct sockaddr_in sin; | |
| 78 | + | |
| 79 | + len = sizeof(sin); | |
| 80 | + if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0) | |
| 81 | + error(sys_errlist[errno]); | |
| 82 | + | |
| 83 | + if(sin.sin_family != AF_INET || len != sizeof(sin)) | |
| 84 | + error("not AF_INET"); | |
| 85 | + | |
| 86 | + *laddr = nhgetl(&sin.sin_addr.s_addr); | |
| 87 | + *lport = nhgets(&sin.sin_port); | |
| 88 | +} | |
| 89 | + | |
| 90 | +void | |
| 91 | +so_listen(int fd) | |
| 92 | +{ | |
| 93 | + if(listen(fd, 5) < 0) | |
| 94 | + error(sys_errlist[errno]); | |
| 95 | +} | |
| 96 | + | |
| 97 | +int | |
| 98 | +so_accept(int fd, unsigned long *raddr, unsigned short *rport) | |
| 99 | +{ | |
| 100 | + int nfd, len; | |
| 101 | + struct sockaddr_in sin; | |
| 102 | + | |
| 103 | + len = sizeof(sin); | |
| 104 | + nfd = accept(fd, (struct sockaddr*)&sin, &len); | |
| 105 | + if(nfd < 0) | |
| 106 | + error(sys_errlist[errno]); | |
| 107 | + | |
| 108 | + if(sin.sin_family != AF_INET || len != sizeof(sin)) | |
| 109 | + error("not AF_INET"); | |
| 110 | + | |
| 111 | + *raddr = nhgetl(&sin.sin_addr.s_addr); | |
| 112 | + *rport = nhgets(&sin.sin_port); | |
| 113 | + return nfd; | |
| 114 | +} | |
| 115 | + | |
| 116 | +void | |
| 117 | +so_bind(int fd, int su, unsigned short port) | |
| 118 | +{ | |
| 119 | + int i, one; | |
| 120 | + struct sockaddr_in sin; | |
| 121 | + | |
| 122 | + one = 1; | |
| 123 | + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0) | |
| 124 | + print("setsockopt: %s", sys_errlist[errno]); | |
| 125 | + | |
| 126 | + if(su) { | |
| 127 | + for(i = 600; i < 1024; i++) { | |
| 128 | + memset(&sin, 0, sizeof(sin)); | |
| 129 | + sin.sin_family = AF_INET; | |
| 130 | + sin.sin_port = i; | |
| 131 | + | |
| 132 | + if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0) | |
| 133 | + return; | |
| 134 | + } | |
| 135 | + error(sys_errlist[errno]); | |
| 136 | + } | |
| 137 | + | |
| 138 | + memset(&sin, 0, sizeof(sin)); | |
| 139 | + sin.sin_family = AF_INET; | |
| 140 | + hnputs(&sin.sin_port, port); | |
| 141 | + | |
| 142 | + if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) | |
| 143 | + error(sys_errlist[errno]); | |
| 144 | +} | |
| 145 | + | |
| 146 | +int | |
| 147 | +so_gethostbyname(char *host, char**hostv, int n) | |
| 148 | +{ | |
| 149 | + int i; | |
| 150 | + char buf[32]; | |
| 151 | + unsigned char *p; | |
| 152 | + struct hostent *hp; | |
| 153 | + | |
| 154 | + hp = gethostbyname(host); | |
| 155 | + if(hp == 0) | |
| 156 | + return 0; | |
| 157 | + | |
| 158 | + for(i = 0; hp->h_addr_list[i] && i < n; i++) { | |
| 159 | + p = (unsigned char*)hp->h_addr_list[i]; | |
| 160 | + sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); | |
| 161 | + hostv[i] = strdup(buf); | |
| 162 | + if(hostv[i] == 0) | |
| 163 | + break; | |
| 164 | + } | |
| 165 | + return i; | |
| 166 | +} | |
| 167 | + | |
| 168 | +char* | |
| 169 | +hostlookup(char *host) | |
| 170 | +{ | |
| 171 | + char buf[100]; | |
| 172 | + uchar *p; | |
| 173 | + HOSTENT *he; | |
| 174 | + | |
| 175 | + he = gethostbyname(host); | |
| 176 | + if(he != 0 && he->h_addr_list[0]) { | |
| 177 | + p = he->h_addr_list[0]; | |
| 178 | + sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]); | |
| 179 | + } else | |
| 180 | + strcpy(buf, host); | |
| 181 | + | |
| 182 | + return strdup(buf); | |
| 183 | +} | |
| 184 | + | |
| 185 | +int | |
| 186 | +so_getservbyname(char *service, char *net, char *port) | |
| 187 | +{ | |
| 188 | + struct servent *s; | |
| 189 | + | |
| 190 | + s = getservbyname(service, net); | |
| 191 | + if(s == 0) | |
| 192 | + return -1; | |
| 193 | + | |
| 194 | + sprint(port, "%d", nhgets(&s->s_port)); | |
| 195 | + return 0; | |
| 196 | +} | |
| 197 | + | |
| 198 | +int | |
| 199 | +so_send(int fd, void *d, int n, int f) | |
| 200 | +{ | |
| 201 | + return send(fd, d, n, f); | |
| 202 | +} | |
| 203 | + | |
| 204 | +int | |
| 205 | +so_recv(int fd, void *d, int n, int f) | |
| 206 | +{ | |
| 207 | + return recv(fd, d, n, f); | |
| 208 | +} | |
| @@ -0,0 +1,936 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#include "devip.h" | |
| 8 | + | |
| 9 | +void hnputl(void *p, unsigned long v); | |
| 10 | +void hnputs(void *p, unsigned short v); | |
| 11 | +unsigned long nhgetl(void *p); | |
| 12 | +unsigned short nhgets(void *p); | |
| 13 | +unsigned long parseip(char *to, char *from); | |
| 14 | +void csclose(Chan*); | |
| 15 | +long csread(Chan*, void*, long, vlong); | |
| 16 | +long cswrite(Chan*, void*, long, vlong); | |
| 17 | + | |
| 18 | +void osipinit(void); | |
| 19 | + | |
| 20 | +enum | |
| 21 | +{ | |
| 22 | + Qtopdir = 1, /* top level directory */ | |
| 23 | + Qcs, | |
| 24 | + Qprotodir, /* directory for a protocol */ | |
| 25 | + Qclonus, | |
| 26 | + Qconvdir, /* directory for a conversation */ | |
| 27 | + Qdata, | |
| 28 | + Qctl, | |
| 29 | + Qstatus, | |
| 30 | + Qremote, | |
| 31 | + Qlocal, | |
| 32 | + Qlisten, | |
| 33 | + | |
| 34 | + MAXPROTO = 4 | |
| 35 | +}; | |
| 36 | +#define TYPE(x) ((int)((x).path & 0xf)) | |
| 37 | +#define CONV(x) ((int)(((x).path >> 4)&0xfff)) | |
| 38 | +#define PROTO(x) ((int)(((x).path >> 16)&0xff)) | |
| 39 | +#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) | |
| 40 | + | |
| 41 | +typedef struct Proto Proto; | |
| 42 | +typedef struct Conv Conv; | |
| 43 | +struct Conv | |
| 44 | +{ | |
| 45 | + int x; | |
| 46 | + Ref r; | |
| 47 | + int sfd; | |
| 48 | + int perm; | |
| 49 | + char owner[KNAMELEN]; | |
| 50 | + char* state; | |
| 51 | + ulong laddr; | |
| 52 | + ushort lport; | |
| 53 | + ulong raddr; | |
| 54 | + ushort rport; | |
| 55 | + int restricted; | |
| 56 | + char cerr[KNAMELEN]; | |
| 57 | + Proto* p; | |
| 58 | +}; | |
| 59 | + | |
| 60 | +struct Proto | |
| 61 | +{ | |
| 62 | + Lock l; | |
| 63 | + int x; | |
| 64 | + int stype; | |
| 65 | + char name[KNAMELEN]; | |
| 66 | + int nc; | |
| 67 | + int maxconv; | |
| 68 | + Conv** conv; | |
| 69 | + Qid qid; | |
| 70 | +}; | |
| 71 | + | |
| 72 | +static int np; | |
| 73 | +static Proto proto[MAXPROTO]; | |
| 74 | +int eipfmt(Fmt*); | |
| 75 | + | |
| 76 | +static Conv* protoclone(Proto*, char*, int); | |
| 77 | +static void setladdr(Conv*); | |
| 78 | + | |
| 79 | +int | |
| 80 | +ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp) | |
| 81 | +{ | |
| 82 | + Qid q; | |
| 83 | + Conv *cv; | |
| 84 | + char *p; | |
| 85 | + | |
| 86 | + USED(nname); | |
| 87 | + q.vers = 0; | |
| 88 | + q.type = 0; | |
| 89 | + switch(TYPE(c->qid)) { | |
| 90 | + case Qtopdir: | |
| 91 | + if(s >= 1+np) | |
| 92 | + return -1; | |
| 93 | + | |
| 94 | + if(s == 0){ | |
| 95 | + q.path = QID(s, 0, Qcs); | |
| 96 | + devdir(c, q, "cs", 0, "network", 0666, dp); | |
| 97 | + }else{ | |
| 98 | + s--; | |
| 99 | + q.path = QID(s, 0, Qprotodir); | |
| 100 | + q.type = QTDIR; | |
| 101 | + devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp); | |
| 102 | + } | |
| 103 | + return 1; | |
| 104 | + case Qprotodir: | |
| 105 | + if(s < proto[PROTO(c->qid)].nc) { | |
| 106 | + cv = proto[PROTO(c->qid)].conv[s]; | |
| 107 | + sprint(up->genbuf, "%d", s); | |
| 108 | + q.path = QID(PROTO(c->qid), s, Qconvdir); | |
| 109 | + q.type = QTDIR; | |
| 110 | + devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp); | |
| 111 | + return 1; | |
| 112 | + } | |
| 113 | + s -= proto[PROTO(c->qid)].nc; | |
| 114 | + switch(s) { | |
| 115 | + default: | |
| 116 | + return -1; | |
| 117 | + case 0: | |
| 118 | + p = "clone"; | |
| 119 | + q.path = QID(PROTO(c->qid), 0, Qclonus); | |
| 120 | + break; | |
| 121 | + } | |
| 122 | + devdir(c, q, p, 0, "network", 0555, dp); | |
| 123 | + return 1; | |
| 124 | + case Qconvdir: | |
| 125 | + cv = proto[PROTO(c->qid)].conv[CONV(c->qid)]; | |
| 126 | + switch(s) { | |
| 127 | + default: | |
| 128 | + return -1; | |
| 129 | + case 0: | |
| 130 | + q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata); | |
| 131 | + devdir(c, q, "data", 0, cv->owner, cv->perm, dp); | |
| 132 | + return 1; | |
| 133 | + case 1: | |
| 134 | + q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl); | |
| 135 | + devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); | |
| 136 | + return 1; | |
| 137 | + case 2: | |
| 138 | + p = "status"; | |
| 139 | + q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus); | |
| 140 | + break; | |
| 141 | + case 3: | |
| 142 | + p = "remote"; | |
| 143 | + q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote); | |
| 144 | + break; | |
| 145 | + case 4: | |
| 146 | + p = "local"; | |
| 147 | + q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal); | |
| 148 | + break; | |
| 149 | + case 5: | |
| 150 | + p = "listen"; | |
| 151 | + q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten); | |
| 152 | + break; | |
| 153 | + } | |
| 154 | + devdir(c, q, p, 0, cv->owner, 0444, dp); | |
| 155 | + return 1; | |
| 156 | + } | |
| 157 | + return -1; | |
| 158 | +} | |
| 159 | + | |
| 160 | +static void | |
| 161 | +newproto(char *name, int type, int maxconv) | |
| 162 | +{ | |
| 163 | + int l; | |
| 164 | + Proto *p; | |
| 165 | + | |
| 166 | + if(np >= MAXPROTO) { | |
| 167 | + print("no %s: increase MAXPROTO", name); | |
| 168 | + return; | |
| 169 | + } | |
| 170 | + | |
| 171 | + p = &proto[np]; | |
| 172 | + strcpy(p->name, name); | |
| 173 | + p->stype = type; | |
| 174 | + p->qid.path = QID(np, 0, Qprotodir); | |
| 175 | + p->qid.type = QTDIR; | |
| 176 | + p->x = np++; | |
| 177 | + p->maxconv = maxconv; | |
| 178 | + l = sizeof(Conv*)*(p->maxconv+1); | |
| 179 | + p->conv = mallocz(l, 1); | |
| 180 | + if(p->conv == 0) | |
| 181 | + panic("no memory"); | |
| 182 | +} | |
| 183 | + | |
| 184 | +void | |
| 185 | +ipinit(void) | |
| 186 | +{ | |
| 187 | + osipinit(); | |
| 188 | + | |
| 189 | + newproto("udp", S_UDP, 10); | |
| 190 | + newproto("tcp", S_TCP, 30); | |
| 191 | + | |
| 192 | + fmtinstall('I', eipfmt); | |
| 193 | + fmtinstall('E', eipfmt); | |
| 194 | + | |
| 195 | +} | |
| 196 | + | |
| 197 | +Chan * | |
| 198 | +ipattach(char *spec) | |
| 199 | +{ | |
| 200 | + Chan *c; | |
| 201 | + | |
| 202 | + c = devattach('I', spec); | |
| 203 | + c->qid.path = QID(0, 0, Qtopdir); | |
| 204 | + c->qid.type = QTDIR; | |
| 205 | + c->qid.vers = 0; | |
| 206 | + return c; | |
| 207 | +} | |
| 208 | + | |
| 209 | +static Walkqid* | |
| 210 | +ipwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 211 | +{ | |
| 212 | + return devwalk(c, nc, name, nname, 0, 0, ipgen); | |
| 213 | +} | |
| 214 | + | |
| 215 | +int | |
| 216 | +ipstat(Chan *c, uchar *dp, int n) | |
| 217 | +{ | |
| 218 | + return devstat(c, dp, n, 0, 0, ipgen); | |
| 219 | +} | |
| 220 | + | |
| 221 | +Chan * | |
| 222 | +ipopen(Chan *c, int omode) | |
| 223 | +{ | |
| 224 | + Proto *p; | |
| 225 | + ulong raddr; | |
| 226 | + ushort rport; | |
| 227 | + int perm, sfd; | |
| 228 | + Conv *cv, *lcv; | |
| 229 | + | |
| 230 | + omode &= 3; | |
| 231 | + switch(omode) { | |
| 232 | + case OREAD: | |
| 233 | + perm = 4; | |
| 234 | + break; | |
| 235 | + case OWRITE: | |
| 236 | + perm = 2; | |
| 237 | + break; | |
| 238 | + case ORDWR: | |
| 239 | + perm = 6; | |
| 240 | + break; | |
| 241 | + } | |
| 242 | + | |
| 243 | + switch(TYPE(c->qid)) { | |
| 244 | + default: | |
| 245 | + break; | |
| 246 | + case Qtopdir: | |
| 247 | + case Qprotodir: | |
| 248 | + case Qconvdir: | |
| 249 | + case Qstatus: | |
| 250 | + case Qremote: | |
| 251 | + case Qlocal: | |
| 252 | + if(omode != OREAD) | |
| 253 | + error(Eperm); | |
| 254 | + break; | |
| 255 | + case Qclonus: | |
| 256 | + p = &proto[PROTO(c->qid)]; | |
| 257 | + cv = protoclone(p, up->user, -1); | |
| 258 | + if(cv == 0) | |
| 259 | + error(Enodev); | |
| 260 | + c->qid.path = QID(p->x, cv->x, Qctl); | |
| 261 | + c->qid.vers = 0; | |
| 262 | + break; | |
| 263 | + case Qdata: | |
| 264 | + case Qctl: | |
| 265 | + p = &proto[PROTO(c->qid)]; | |
| 266 | + lock(&p->l); | |
| 267 | + cv = p->conv[CONV(c->qid)]; | |
| 268 | + lock(&cv->r.lk); | |
| 269 | + if((perm & (cv->perm>>6)) != perm) { | |
| 270 | + if(strcmp(up->user, cv->owner) != 0 || | |
| 271 | + (perm & cv->perm) != perm) { | |
| 272 | + unlock(&cv->r.lk); | |
| 273 | + unlock(&p->l); | |
| 274 | + error(Eperm); | |
| 275 | + } | |
| 276 | + } | |
| 277 | + cv->r.ref++; | |
| 278 | + if(cv->r.ref == 1) { | |
| 279 | + memmove(cv->owner, up->user, KNAMELEN); | |
| 280 | + cv->perm = 0660; | |
| 281 | + } | |
| 282 | + unlock(&cv->r.lk); | |
| 283 | + unlock(&p->l); | |
| 284 | + break; | |
| 285 | + case Qlisten: | |
| 286 | + p = &proto[PROTO(c->qid)]; | |
| 287 | + lcv = p->conv[CONV(c->qid)]; | |
| 288 | + sfd = so_accept(lcv->sfd, &raddr, &rport); | |
| 289 | + cv = protoclone(p, up->user, sfd); | |
| 290 | + if(cv == 0) { | |
| 291 | + close(sfd); | |
| 292 | + error(Enodev); | |
| 293 | + } | |
| 294 | + cv->raddr = raddr; | |
| 295 | + cv->rport = rport; | |
| 296 | + setladdr(cv); | |
| 297 | + cv->state = "Established"; | |
| 298 | + c->qid.path = QID(p->x, cv->x, Qctl); | |
| 299 | + break; | |
| 300 | + } | |
| 301 | + c->mode = openmode(omode); | |
| 302 | + c->flag |= COPEN; | |
| 303 | + c->offset = 0; | |
| 304 | + return c; | |
| 305 | +} | |
| 306 | + | |
| 307 | +void | |
| 308 | +ipclose(Chan *c) | |
| 309 | +{ | |
| 310 | + Conv *cc; | |
| 311 | + | |
| 312 | + switch(TYPE(c->qid)) { | |
| 313 | + case Qcs: | |
| 314 | + csclose(c); | |
| 315 | + break; | |
| 316 | + case Qdata: | |
| 317 | + case Qctl: | |
| 318 | + if((c->flag & COPEN) == 0) | |
| 319 | + break; | |
| 320 | + cc = proto[PROTO(c->qid)].conv[CONV(c->qid)]; | |
| 321 | + if(decref(&cc->r) != 0) | |
| 322 | + break; | |
| 323 | + strcpy(cc->owner, "network"); | |
| 324 | + cc->perm = 0666; | |
| 325 | + cc->state = "Closed"; | |
| 326 | + cc->laddr = 0; | |
| 327 | + cc->raddr = 0; | |
| 328 | + cc->lport = 0; | |
| 329 | + cc->rport = 0; | |
| 330 | + close(cc->sfd); | |
| 331 | + break; | |
| 332 | + } | |
| 333 | +} | |
| 334 | + | |
| 335 | +long | |
| 336 | +ipread(Chan *ch, void *a, long n, vlong offset) | |
| 337 | +{ | |
| 338 | + int r; | |
| 339 | + Conv *c; | |
| 340 | + Proto *x; | |
| 341 | + uchar ip[4]; | |
| 342 | + char buf[128], *p; | |
| 343 | + | |
| 344 | +/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/ | |
| 345 | + p = a; | |
| 346 | + switch(TYPE(ch->qid)) { | |
| 347 | + default: | |
| 348 | + error(Eperm); | |
| 349 | + case Qcs: | |
| 350 | + return csread(ch, a, n, offset); | |
| 351 | + case Qprotodir: | |
| 352 | + case Qtopdir: | |
| 353 | + case Qconvdir: | |
| 354 | + return devdirread(ch, a, n, 0, 0, ipgen); | |
| 355 | + case Qctl: | |
| 356 | + sprint(buf, "%d", CONV(ch->qid)); | |
| 357 | + return readstr(offset, p, n, buf); | |
| 358 | + case Qremote: | |
| 359 | + c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; | |
| 360 | + hnputl(ip, c->raddr); | |
| 361 | + sprint(buf, "%I!%d\n", ip, c->rport); | |
| 362 | + return readstr(offset, p, n, buf); | |
| 363 | + case Qlocal: | |
| 364 | + c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; | |
| 365 | + hnputl(ip, c->laddr); | |
| 366 | + sprint(buf, "%I!%d\n", ip, c->lport); | |
| 367 | + return readstr(offset, p, n, buf); | |
| 368 | + case Qstatus: | |
| 369 | + x = &proto[PROTO(ch->qid)]; | |
| 370 | + c = x->conv[CONV(ch->qid)]; | |
| 371 | + sprint(buf, "%s/%d %d %s \n", | |
| 372 | + c->p->name, c->x, c->r.ref, c->state); | |
| 373 | + return readstr(offset, p, n, buf); | |
| 374 | + case Qdata: | |
| 375 | + c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)]; | |
| 376 | + r = so_recv(c->sfd, a, n, 0); | |
| 377 | + if(r < 0){ | |
| 378 | + oserrstr(); | |
| 379 | + nexterror(); | |
| 380 | + } | |
| 381 | + return r; | |
| 382 | + } | |
| 383 | +} | |
| 384 | + | |
| 385 | +static void | |
| 386 | +setladdr(Conv *c) | |
| 387 | +{ | |
| 388 | + so_getsockname(c->sfd, &c->laddr, &c->lport); | |
| 389 | +} | |
| 390 | + | |
| 391 | +static void | |
| 392 | +setlport(Conv *c) | |
| 393 | +{ | |
| 394 | + if(c->restricted == 0 && c->lport == 0) | |
| 395 | + return; | |
| 396 | + | |
| 397 | + so_bind(c->sfd, c->restricted, c->lport); | |
| 398 | +} | |
| 399 | + | |
| 400 | +static void | |
| 401 | +setladdrport(Conv *c, char *str) | |
| 402 | +{ | |
| 403 | + char *p, addr[4]; | |
| 404 | + | |
| 405 | + p = strchr(str, '!'); | |
| 406 | + if(p == 0) { | |
| 407 | + p = str; | |
| 408 | + c->laddr = 0; | |
| 409 | + } | |
| 410 | + else { | |
| 411 | + *p++ = 0; | |
| 412 | + parseip(addr, str); | |
| 413 | + c->laddr = nhgetl((uchar*)addr); | |
| 414 | + } | |
| 415 | + if(*p == '*') | |
| 416 | + c->lport = 0; | |
| 417 | + else | |
| 418 | + c->lport = atoi(p); | |
| 419 | + | |
| 420 | + setlport(c); | |
| 421 | +} | |
| 422 | + | |
| 423 | +static char* | |
| 424 | +setraddrport(Conv *c, char *str) | |
| 425 | +{ | |
| 426 | + char *p, addr[4]; | |
| 427 | + | |
| 428 | + p = strchr(str, '!'); | |
| 429 | + if(p == 0) | |
| 430 | + return "malformed address"; | |
| 431 | + *p++ = 0; | |
| 432 | + parseip(addr, str); | |
| 433 | + c->raddr = nhgetl((uchar*)addr); | |
| 434 | + c->rport = atoi(p); | |
| 435 | + p = strchr(p, '!'); | |
| 436 | + if(p) { | |
| 437 | + if(strcmp(p, "!r") == 0) | |
| 438 | + c->restricted = 1; | |
| 439 | + } | |
| 440 | + return 0; | |
| 441 | +} | |
| 442 | + | |
| 443 | +long | |
| 444 | +ipwrite(Chan *ch, void *a, long n, vlong offset) | |
| 445 | +{ | |
| 446 | + Conv *c; | |
| 447 | + Proto *x; | |
| 448 | + int r, nf; | |
| 449 | + char *p, *fields[3], buf[128]; | |
| 450 | + | |
| 451 | + switch(TYPE(ch->qid)) { | |
| 452 | + default: | |
| 453 | + error(Eperm); | |
| 454 | + case Qcs: | |
| 455 | + return cswrite(ch, a, n, offset); | |
| 456 | + case Qctl: | |
| 457 | + x = &proto[PROTO(ch->qid)]; | |
| 458 | + c = x->conv[CONV(ch->qid)]; | |
| 459 | + if(n > sizeof(buf)-1) | |
| 460 | + n = sizeof(buf)-1; | |
| 461 | + memmove(buf, a, n); | |
| 462 | + buf[n] = '\0'; | |
| 463 | + | |
| 464 | + nf = tokenize(buf, fields, 3); | |
| 465 | + if(strcmp(fields[0], "connect") == 0){ | |
| 466 | + switch(nf) { | |
| 467 | + default: | |
| 468 | + error("bad args to connect"); | |
| 469 | + case 2: | |
| 470 | + p = setraddrport(c, fields[1]); | |
| 471 | + if(p != 0) | |
| 472 | + error(p); | |
| 473 | + break; | |
| 474 | + case 3: | |
| 475 | + p = setraddrport(c, fields[1]); | |
| 476 | + if(p != 0) | |
| 477 | + error(p); | |
| 478 | + c->lport = atoi(fields[2]); | |
| 479 | + setlport(c); | |
| 480 | + break; | |
| 481 | + } | |
| 482 | + so_connect(c->sfd, c->raddr, c->rport); | |
| 483 | + setladdr(c); | |
| 484 | + c->state = "Established"; | |
| 485 | + return n; | |
| 486 | + } | |
| 487 | + if(strcmp(fields[0], "announce") == 0) { | |
| 488 | + switch(nf){ | |
| 489 | + default: | |
| 490 | + error("bad args to announce"); | |
| 491 | + case 2: | |
| 492 | + setladdrport(c, fields[1]); | |
| 493 | + break; | |
| 494 | + } | |
| 495 | + so_listen(c->sfd); | |
| 496 | + c->state = "Announced"; | |
| 497 | + return n; | |
| 498 | + } | |
| 499 | + if(strcmp(fields[0], "bind") == 0){ | |
| 500 | + switch(nf){ | |
| 501 | + default: | |
| 502 | + error("bad args to bind"); | |
| 503 | + case 2: | |
| 504 | + c->lport = atoi(fields[1]); | |
| 505 | + break; | |
| 506 | + } | |
| 507 | + setlport(c); | |
| 508 | + return n; | |
| 509 | + } | |
| 510 | + error("bad control message"); | |
| 511 | + case Qdata: | |
| 512 | + x = &proto[PROTO(ch->qid)]; | |
| 513 | + c = x->conv[CONV(ch->qid)]; | |
| 514 | + r = so_send(c->sfd, a, n, 0); | |
| 515 | + if(r < 0){ | |
| 516 | + oserrstr(); | |
| 517 | + nexterror(); | |
| 518 | + } | |
| 519 | + return r; | |
| 520 | + } | |
| 521 | + return n; | |
| 522 | +} | |
| 523 | + | |
| 524 | +static Conv* | |
| 525 | +protoclone(Proto *p, char *user, int nfd) | |
| 526 | +{ | |
| 527 | + Conv *c, **pp, **ep; | |
| 528 | + | |
| 529 | + c = 0; | |
| 530 | + lock(&p->l); | |
| 531 | + if(waserror()) { | |
| 532 | + unlock(&p->l); | |
| 533 | + nexterror(); | |
| 534 | + } | |
| 535 | + ep = &p->conv[p->maxconv]; | |
| 536 | + for(pp = p->conv; pp < ep; pp++) { | |
| 537 | + c = *pp; | |
| 538 | + if(c == 0) { | |
| 539 | + c = mallocz(sizeof(Conv), 1); | |
| 540 | + if(c == 0) | |
| 541 | + error(Enomem); | |
| 542 | + lock(&c->r.lk); | |
| 543 | + c->r.ref = 1; | |
| 544 | + c->p = p; | |
| 545 | + c->x = pp - p->conv; | |
| 546 | + p->nc++; | |
| 547 | + *pp = c; | |
| 548 | + break; | |
| 549 | + } | |
| 550 | + lock(&c->r.lk); | |
| 551 | + if(c->r.ref == 0) { | |
| 552 | + c->r.ref++; | |
| 553 | + break; | |
| 554 | + } | |
| 555 | + unlock(&c->r.lk); | |
| 556 | + } | |
| 557 | + if(pp >= ep) { | |
| 558 | + unlock(&p->l); | |
| 559 | + poperror(); | |
| 560 | + return 0; | |
| 561 | + } | |
| 562 | + | |
| 563 | + strcpy(c->owner, user); | |
| 564 | + c->perm = 0660; | |
| 565 | + c->state = "Closed"; | |
| 566 | + c->restricted = 0; | |
| 567 | + c->laddr = 0; | |
| 568 | + c->raddr = 0; | |
| 569 | + c->lport = 0; | |
| 570 | + c->rport = 0; | |
| 571 | + c->sfd = nfd; | |
| 572 | + if(nfd == -1) | |
| 573 | + c->sfd = so_socket(p->stype); | |
| 574 | + | |
| 575 | + unlock(&c->r.lk); | |
| 576 | + unlock(&p->l); | |
| 577 | + poperror(); | |
| 578 | + return c; | |
| 579 | +} | |
| 580 | + | |
| 581 | +enum | |
| 582 | +{ | |
| 583 | + Isprefix= 16, | |
| 584 | +}; | |
| 585 | + | |
| 586 | +uchar prefixvals[256] = | |
| 587 | +{ | |
| 588 | +/*0x00*/ 0 | Isprefix, | |
| 589 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 590 | +/*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 591 | +/*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 592 | +/*0x30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 593 | +/*0x40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 594 | +/*0x50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 595 | +/*0x60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 596 | +/*0x70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 597 | +/*0x80*/ 1 | Isprefix, | |
| 598 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 599 | +/*0x90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 600 | +/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 601 | +/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 602 | +/*0xC0*/ 2 | Isprefix, | |
| 603 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 604 | +/*0xD0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 605 | +/*0xE0*/ 3 | Isprefix, | |
| 606 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 607 | +/*0xF0*/ 4 | Isprefix, | |
| 608 | + 0, 0, 0, 0, 0, 0, 0, | |
| 609 | +/*0xF8*/ 5 | Isprefix, | |
| 610 | + 0, 0, 0, | |
| 611 | +/*0xFC*/ 6 | Isprefix, | |
| 612 | + 0, | |
| 613 | +/*0xFE*/ 7 | Isprefix, | |
| 614 | +/*0xFF*/ 8 | Isprefix, | |
| 615 | +}; | |
| 616 | + | |
| 617 | +int | |
| 618 | +eipfmt(Fmt *f) | |
| 619 | +{ | |
| 620 | + char buf[5*8]; | |
| 621 | + static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux"; | |
| 622 | + static char *ifmt = "%d.%d.%d.%d"; | |
| 623 | + uchar *p, ip[16]; | |
| 624 | + ulong *lp; | |
| 625 | + ushort s; | |
| 626 | + int i, j, n, eln, eli; | |
| 627 | + ulong ul; | |
| 628 | + | |
| 629 | + switch(f->r) { | |
| 630 | + case 'E': /* Ethernet address */ | |
| 631 | + p = va_arg(f->args, uchar*); | |
| 632 | + snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]); | |
| 633 | + return fmtstrcpy(f, buf); | |
| 634 | + | |
| 635 | + case 'I': | |
| 636 | + ul = va_arg(f->args, ulong); | |
| 637 | + hnputl(ip, ul); | |
| 638 | + snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]); | |
| 639 | + return fmtstrcpy(f, buf); | |
| 640 | + } | |
| 641 | + return fmtstrcpy(f, "(eipfmt)"); | |
| 642 | +} | |
| 643 | + | |
| 644 | +void | |
| 645 | +hnputl(void *p, unsigned long v) | |
| 646 | +{ | |
| 647 | + unsigned char *a; | |
| 648 | + | |
| 649 | + a = p; | |
| 650 | + a[0] = v>>24; | |
| 651 | + a[1] = v>>16; | |
| 652 | + a[2] = v>>8; | |
| 653 | + a[3] = v; | |
| 654 | +} | |
| 655 | + | |
| 656 | +void | |
| 657 | +hnputs(void *p, unsigned short v) | |
| 658 | +{ | |
| 659 | + unsigned char *a; | |
| 660 | + | |
| 661 | + a = p; | |
| 662 | + a[0] = v>>8; | |
| 663 | + a[1] = v; | |
| 664 | +} | |
| 665 | + | |
| 666 | +unsigned long | |
| 667 | +nhgetl(void *p) | |
| 668 | +{ | |
| 669 | + unsigned char *a; | |
| 670 | + a = p; | |
| 671 | + return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0); | |
| 672 | +} | |
| 673 | + | |
| 674 | +unsigned short | |
| 675 | +nhgets(void *p) | |
| 676 | +{ | |
| 677 | + unsigned char *a; | |
| 678 | + a = p; | |
| 679 | + return (a[0]<<8)|(a[1]<<0); | |
| 680 | +} | |
| 681 | + | |
| 682 | +#define CLASS(p) ((*(unsigned char*)(p))>>6) | |
| 683 | + | |
| 684 | +unsigned long | |
| 685 | +parseip(char *to, char *from) | |
| 686 | +{ | |
| 687 | + int i; | |
| 688 | + char *p; | |
| 689 | + | |
| 690 | + p = from; | |
| 691 | + memset(to, 0, 4); | |
| 692 | + for(i = 0; i < 4 && *p; i++){ | |
| 693 | + to[i] = strtoul(p, &p, 0); | |
| 694 | + if(*p == '.') | |
| 695 | + p++; | |
| 696 | + } | |
| 697 | + switch(CLASS(to)){ | |
| 698 | + case 0: /* class A - 1 byte net */ | |
| 699 | + case 1: | |
| 700 | + if(i == 3){ | |
| 701 | + to[3] = to[2]; | |
| 702 | + to[2] = to[1]; | |
| 703 | + to[1] = 0; | |
| 704 | + } else if (i == 2){ | |
| 705 | + to[3] = to[1]; | |
| 706 | + to[1] = 0; | |
| 707 | + } | |
| 708 | + break; | |
| 709 | + case 2: /* class B - 2 byte net */ | |
| 710 | + if(i == 3){ | |
| 711 | + to[3] = to[2]; | |
| 712 | + to[2] = 0; | |
| 713 | + } | |
| 714 | + break; | |
| 715 | + } | |
| 716 | + return nhgetl(to); | |
| 717 | +} | |
| 718 | + | |
| 719 | +void | |
| 720 | +csclose(Chan *c) | |
| 721 | +{ | |
| 722 | + free(c->aux); | |
| 723 | +} | |
| 724 | + | |
| 725 | +long | |
| 726 | +csread(Chan *c, void *a, long n, vlong offset) | |
| 727 | +{ | |
| 728 | + if(c->aux == nil) | |
| 729 | + return 0; | |
| 730 | + return readstr(offset, a, n, c->aux); | |
| 731 | +} | |
| 732 | + | |
| 733 | +static struct | |
| 734 | +{ | |
| 735 | + char *name; | |
| 736 | + uint num; | |
| 737 | +} tab[] = { | |
| 738 | + "cs", 1, | |
| 739 | + "echo", 7, | |
| 740 | + "discard", 9, | |
| 741 | + "systat", 11, | |
| 742 | + "daytime", 13, | |
| 743 | + "netstat", 15, | |
| 744 | + "chargen", 19, | |
| 745 | + "ftp-data", 20, | |
| 746 | + "ftp", 21, | |
| 747 | + "ssh", 22, | |
| 748 | + "telnet", 23, | |
| 749 | + "smtp", 25, | |
| 750 | + "time", 37, | |
| 751 | + "whois", 43, | |
| 752 | + "dns", 53, | |
| 753 | + "domain", 53, | |
| 754 | + "uucp", 64, | |
| 755 | + "gopher", 70, | |
| 756 | + "rje", 77, | |
| 757 | + "finger", 79, | |
| 758 | + "http", 80, | |
| 759 | + "link", 87, | |
| 760 | + "supdup", 95, | |
| 761 | + "hostnames", 101, | |
| 762 | + "iso-tsap", 102, | |
| 763 | + "x400", 103, | |
| 764 | + "x400-snd", 104, | |
| 765 | + "csnet-ns", 105, | |
| 766 | + "pop-2", 109, | |
| 767 | + "pop3", 110, | |
| 768 | + "portmap", 111, | |
| 769 | + "uucp-path", 117, | |
| 770 | + "nntp", 119, | |
| 771 | + "netbios", 139, | |
| 772 | + "imap4", 143, | |
| 773 | + "NeWS", 144, | |
| 774 | + "print-srv", 170, | |
| 775 | + "z39.50", 210, | |
| 776 | + "fsb", 400, | |
| 777 | + "sysmon", 401, | |
| 778 | + "proxy", 402, | |
| 779 | + "proxyd", 404, | |
| 780 | + "https", 443, | |
| 781 | + "cifs", 445, | |
| 782 | + "ssmtp", 465, | |
| 783 | + "rexec", 512, | |
| 784 | + "login", 513, | |
| 785 | + "shell", 514, | |
| 786 | + "printer", 515, | |
| 787 | + "courier", 530, | |
| 788 | + "cscan", 531, | |
| 789 | + "uucp", 540, | |
| 790 | + "snntp", 563, | |
| 791 | + "9fs", 564, | |
| 792 | + "whoami", 565, | |
| 793 | + "guard", 566, | |
| 794 | + "ticket", 567, | |
| 795 | + "dlsftp", 666, | |
| 796 | + "fmclient", 729, | |
| 797 | + "imaps", 993, | |
| 798 | + "pop3s", 995, | |
| 799 | + "ingreslock", 1524, | |
| 800 | + "pptp", 1723, | |
| 801 | + "nfs", 2049, | |
| 802 | + "webster", 2627, | |
| 803 | + "weather", 3000, | |
| 804 | + "secstore", 5356, | |
| 805 | + "Xdisplay", 6000, | |
| 806 | + "styx", 6666, | |
| 807 | + "mpeg", 6667, | |
| 808 | + "rstyx", 6668, | |
| 809 | + "infdb", 6669, | |
| 810 | + "infsigner", 6671, | |
| 811 | + "infcsigner", 6672, | |
| 812 | + "inflogin", 6673, | |
| 813 | + "bandt", 7330, | |
| 814 | + "face", 32000, | |
| 815 | + "dhashgate", 11978, | |
| 816 | + "exportfs", 17007, | |
| 817 | + "rexexec", 17009, | |
| 818 | + "ncpu", 17010, | |
| 819 | + "cpu", 17013, | |
| 820 | + "glenglenda1", 17020, | |
| 821 | + "glenglenda2", 17021, | |
| 822 | + "glenglenda3", 17022, | |
| 823 | + "glenglenda4", 17023, | |
| 824 | + "glenglenda5", 17024, | |
| 825 | + "glenglenda6", 17025, | |
| 826 | + "glenglenda7", 17026, | |
| 827 | + "glenglenda8", 17027, | |
| 828 | + "glenglenda9", 17028, | |
| 829 | + "glenglenda10", 17029, | |
| 830 | + "flyboy", 17032, | |
| 831 | + "dlsftp", 17033, | |
| 832 | + "venti", 17034, | |
| 833 | + "wiki", 17035, | |
| 834 | + "vica", 17036, | |
| 835 | + 0 | |
| 836 | +}; | |
| 837 | + | |
| 838 | +static int | |
| 839 | +lookupport(char *s) | |
| 840 | +{ | |
| 841 | + int i; | |
| 842 | + char buf[10], *p; | |
| 843 | + | |
| 844 | + i = strtol(s, &p, 0); | |
| 845 | + if(*s && *p == 0) | |
| 846 | + return i; | |
| 847 | + | |
| 848 | + i = so_getservbyname(s, "tcp", buf); | |
| 849 | + if(i != -1) | |
| 850 | + return atoi(buf); | |
| 851 | + for(i=0; tab[i].name; i++) | |
| 852 | + if(strcmp(s, tab[i].name) == 0) | |
| 853 | + return tab[i].num; | |
| 854 | + return 0; | |
| 855 | +} | |
| 856 | + | |
| 857 | +static ulong | |
| 858 | +lookuphost(char *s) | |
| 859 | +{ | |
| 860 | + char to[4]; | |
| 861 | + ulong ip; | |
| 862 | + | |
| 863 | + memset(to, 0, sizeof to); | |
| 864 | + parseip(to, s); | |
| 865 | + ip = nhgetl(to); | |
| 866 | + if(ip != 0) | |
| 867 | + return ip; | |
| 868 | + if((s = hostlookup(s)) == nil) | |
| 869 | + return 0; | |
| 870 | + parseip(to, s); | |
| 871 | + ip = nhgetl(to); | |
| 872 | + free(s); | |
| 873 | + return ip; | |
| 874 | +} | |
| 875 | + | |
| 876 | +long | |
| 877 | +cswrite(Chan *c, void *a, long n, vlong offset) | |
| 878 | +{ | |
| 879 | + char *f[4]; | |
| 880 | + char *s, *ns; | |
| 881 | + ulong ip; | |
| 882 | + int nf, port; | |
| 883 | + | |
| 884 | + s = malloc(n+1); | |
| 885 | + if(s == nil) | |
| 886 | + error(Enomem); | |
| 887 | + if(waserror()){ | |
| 888 | + free(s); | |
| 889 | + nexterror(); | |
| 890 | + } | |
| 891 | + memmove(s, a, n); | |
| 892 | + s[n] = 0; | |
| 893 | + nf = getfields(s, f, nelem(f), 0, "!"); | |
| 894 | + if(nf != 3) | |
| 895 | + error("can't translate"); | |
| 896 | + | |
| 897 | + port = lookupport(f[2]); | |
| 898 | + if(port <= 0) | |
| 899 | + error("no translation for port found"); | |
| 900 | + | |
| 901 | + ip = lookuphost(f[1]); | |
| 902 | + if(ip == 0) | |
| 903 | + error("no translation for host found"); | |
| 904 | + | |
| 905 | + ns = smprint("/net/%s/clone %I!%d", f[0], ip, port); | |
| 906 | + if(ns == nil) | |
| 907 | + error(Enomem); | |
| 908 | + free(c->aux); | |
| 909 | + c->aux = ns; | |
| 910 | + poperror(); | |
| 911 | + free(s); | |
| 912 | + return n; | |
| 913 | +} | |
| 914 | + | |
| 915 | +Dev ipdevtab = | |
| 916 | +{ | |
| 917 | + 'I', | |
| 918 | + "ip", | |
| 919 | + | |
| 920 | + devreset, | |
| 921 | + ipinit, | |
| 922 | + devshutdown, | |
| 923 | + ipattach, | |
| 924 | + ipwalk, | |
| 925 | + ipstat, | |
| 926 | + ipopen, | |
| 927 | + devcreate, | |
| 928 | + ipclose, | |
| 929 | + ipread, | |
| 930 | + devbread, | |
| 931 | + ipwrite, | |
| 932 | + devbwrite, | |
| 933 | + devremove, | |
| 934 | + devwstat, | |
| 935 | +}; | |
| 936 | + | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +enum | |
| 2 | +{ | |
| 3 | + S_TCP, | |
| 4 | + S_UDP | |
| 5 | +}; | |
| 6 | + | |
| 7 | +int so_socket(int type); | |
| 8 | +void so_connect(int, unsigned long, unsigned short); | |
| 9 | +void so_getsockname(int, unsigned long*, unsigned short*); | |
| 10 | +void so_bind(int, int, unsigned short); | |
| 11 | +void so_listen(int); | |
| 12 | +int so_accept(int, unsigned long*, unsigned short*); | |
| 13 | +int so_getservbyname(char*, char*, char*); | |
| 14 | +int so_gethostbyname(char*, char**, int); | |
| 15 | + | |
| 16 | +char* hostlookup(char*); | |
| 17 | + | |
| @@ -0,0 +1,1214 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +/* | |
| 8 | + * References are managed as follows: | |
| 9 | + * The channel to the server - a network connection or pipe - has one | |
| 10 | + * reference for every Chan open on the server. The server channel has | |
| 11 | + * c->mux set to the Mnt used for muxing control to that server. Mnts | |
| 12 | + * have no reference count; they go away when c goes away. | |
| 13 | + * Each channel derived from the mount point has mchan set to c, | |
| 14 | + * and increfs/decrefs mchan to manage references on the server | |
| 15 | + * connection. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#define MAXRPC (IOHDRSZ+8192) | |
| 19 | + | |
| 20 | +struct Mntrpc | |
| 21 | +{ | |
| 22 | + Chan* c; /* Channel for whom we are working */ | |
| 23 | + Mntrpc* list; /* Free/pending list */ | |
| 24 | + Fcall request; /* Outgoing file system protocol message */ | |
| 25 | + Fcall reply; /* Incoming reply */ | |
| 26 | + Mnt* m; /* Mount device during rpc */ | |
| 27 | + Rendez r; /* Place to hang out */ | |
| 28 | + uchar* rpc; /* I/O Data buffer */ | |
| 29 | + uint rpclen; /* len of buffer */ | |
| 30 | + Block *b; /* reply blocks */ | |
| 31 | + char done; /* Rpc completed */ | |
| 32 | + uvlong stime; /* start time for mnt statistics */ | |
| 33 | + ulong reqlen; /* request length for mnt statistics */ | |
| 34 | + ulong replen; /* reply length for mnt statistics */ | |
| 35 | + Mntrpc* flushed; /* message this one flushes */ | |
| 36 | +}; | |
| 37 | + | |
| 38 | +enum | |
| 39 | +{ | |
| 40 | + TAGSHIFT = 5, /* ulong has to be 32 bits */ | |
| 41 | + TAGMASK = (1<<TAGSHIFT)-1, | |
| 42 | + NMASK = (64*1024)>>TAGSHIFT, | |
| 43 | +}; | |
| 44 | + | |
| 45 | +struct Mntalloc | |
| 46 | +{ | |
| 47 | + Lock lk; | |
| 48 | + Mnt* list; /* Mount devices in use */ | |
| 49 | + Mnt* mntfree; /* Free list */ | |
| 50 | + Mntrpc* rpcfree; | |
| 51 | + int nrpcfree; | |
| 52 | + int nrpcused; | |
| 53 | + ulong id; | |
| 54 | + ulong tagmask[NMASK]; | |
| 55 | +}mntalloc; | |
| 56 | + | |
| 57 | +void mattach(Mnt*, Chan*, char*); | |
| 58 | +Mnt* mntchk(Chan*); | |
| 59 | +void mntdirfix(uchar*, Chan*); | |
| 60 | +Mntrpc* mntflushalloc(Mntrpc*, ulong); | |
| 61 | +void mntflushfree(Mnt*, Mntrpc*); | |
| 62 | +void mntfree(Mntrpc*); | |
| 63 | +void mntgate(Mnt*); | |
| 64 | +void mntpntfree(Mnt*); | |
| 65 | +void mntqrm(Mnt*, Mntrpc*); | |
| 66 | +Mntrpc* mntralloc(Chan*, ulong); | |
| 67 | +long mntrdwr(int, Chan*, void*, long, vlong); | |
| 68 | +int mntrpcread(Mnt*, Mntrpc*); | |
| 69 | +void mountio(Mnt*, Mntrpc*); | |
| 70 | +void mountmux(Mnt*, Mntrpc*); | |
| 71 | +void mountrpc(Mnt*, Mntrpc*); | |
| 72 | +int rpcattn(void*); | |
| 73 | +Chan* mntchan(void); | |
| 74 | + | |
| 75 | +char Esbadstat[] = "invalid directory entry received from server"; | |
| 76 | +char Enoversion[] = "version not established for mount channel"; | |
| 77 | + | |
| 78 | + | |
| 79 | +void (*mntstats)(int, Chan*, uvlong, ulong); | |
| 80 | + | |
| 81 | +static void | |
| 82 | +mntreset(void) | |
| 83 | +{ | |
| 84 | + mntalloc.id = 1; | |
| 85 | + mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */ | |
| 86 | + mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */ | |
| 87 | + fmtinstall('F', fcallfmt); | |
| 88 | + fmtinstall('D', dirfmt); | |
| 89 | +/* We can't install %M since eipfmt does and is used in the kernel [sape] */ | |
| 90 | + | |
| 91 | + cinit(); | |
| 92 | +} | |
| 93 | + | |
| 94 | +/* | |
| 95 | + * Version is not multiplexed: message sent only once per connection. | |
| 96 | + */ | |
| 97 | +long | |
| 98 | +mntversion(Chan *c, char *version, int msize, int returnlen) | |
| 99 | +{ | |
| 100 | + Fcall f; | |
| 101 | + uchar *msg; | |
| 102 | + Mnt *m; | |
| 103 | + char *v; | |
| 104 | + long k, l; | |
| 105 | + uvlong oo; | |
| 106 | + char buf[128]; | |
| 107 | + | |
| 108 | + qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */ | |
| 109 | + if(waserror()){ | |
| 110 | + qunlock(&c->umqlock); | |
| 111 | + nexterror(); | |
| 112 | + } | |
| 113 | + | |
| 114 | + /* defaults */ | |
| 115 | + if(msize == 0) | |
| 116 | + msize = MAXRPC; | |
| 117 | + if(msize > c->iounit && c->iounit != 0) | |
| 118 | + msize = c->iounit; | |
| 119 | + v = version; | |
| 120 | + if(v == nil || v[0] == '\0') | |
| 121 | + v = VERSION9P; | |
| 122 | + | |
| 123 | + /* validity */ | |
| 124 | + if(msize < 0) | |
| 125 | + error("bad iounit in version call"); | |
| 126 | + if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0) | |
| 127 | + error("bad 9P version specification"); | |
| 128 | + | |
| 129 | + m = c->mux; | |
| 130 | + | |
| 131 | + if(m != nil){ | |
| 132 | + qunlock(&c->umqlock); | |
| 133 | + poperror(); | |
| 134 | + | |
| 135 | + strecpy(buf, buf+sizeof buf, m->version); | |
| 136 | + k = strlen(buf); | |
| 137 | + if(strncmp(buf, v, k) != 0){ | |
| 138 | + snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v); | |
| 139 | + error(buf); | |
| 140 | + } | |
| 141 | + if(returnlen > 0){ | |
| 142 | + if(returnlen < k) | |
| 143 | + error(Eshort); | |
| 144 | + memmove(version, buf, k); | |
| 145 | + } | |
| 146 | + return k; | |
| 147 | + } | |
| 148 | + | |
| 149 | + f.type = Tversion; | |
| 150 | + f.tag = NOTAG; | |
| 151 | + f.msize = msize; | |
| 152 | + f.version = v; | |
| 153 | + msg = malloc(8192+IOHDRSZ); | |
| 154 | + if(msg == nil) | |
| 155 | + exhausted("version memory"); | |
| 156 | + if(waserror()){ | |
| 157 | + free(msg); | |
| 158 | + nexterror(); | |
| 159 | + } | |
| 160 | + k = convS2M(&f, msg, 8192+IOHDRSZ); | |
| 161 | + if(k == 0) | |
| 162 | + error("bad fversion conversion on send"); | |
| 163 | + | |
| 164 | + lock(&c->ref.lk); | |
| 165 | + oo = c->offset; | |
| 166 | + c->offset += k; | |
| 167 | + unlock(&c->ref.lk); | |
| 168 | + | |
| 169 | + l = devtab[c->type]->write(c, msg, k, oo); | |
| 170 | + | |
| 171 | + if(l < k){ | |
| 172 | + lock(&c->ref.lk); | |
| 173 | + c->offset -= k - l; | |
| 174 | + unlock(&c->ref.lk); | |
| 175 | + error("short write in fversion"); | |
| 176 | + } | |
| 177 | + | |
| 178 | + /* message sent; receive and decode reply */ | |
| 179 | + k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset); | |
| 180 | + if(k <= 0) | |
| 181 | + error("EOF receiving fversion reply"); | |
| 182 | + | |
| 183 | + lock(&c->ref.lk); | |
| 184 | + c->offset += k; | |
| 185 | + unlock(&c->ref.lk); | |
| 186 | + | |
| 187 | + l = convM2S(msg, k, &f); | |
| 188 | + if(l != k) | |
| 189 | + error("bad fversion conversion on reply"); | |
| 190 | + if(f.type != Rversion){ | |
| 191 | + if(f.type == Rerror) | |
| 192 | + error(f.ename); | |
| 193 | + error("unexpected reply type in fversion"); | |
| 194 | + } | |
| 195 | + if(f.msize > msize) | |
| 196 | + error("server tries to increase msize in fversion"); | |
| 197 | + if(f.msize<256 || f.msize>1024*1024) | |
| 198 | + error("nonsense value of msize in fversion"); | |
| 199 | + if(strncmp(f.version, v, strlen(f.version)) != 0) | |
| 200 | + error("bad 9P version returned from server"); | |
| 201 | + | |
| 202 | + /* now build Mnt associated with this connection */ | |
| 203 | + lock(&mntalloc.lk); | |
| 204 | + m = mntalloc.mntfree; | |
| 205 | + if(m != 0) | |
| 206 | + mntalloc.mntfree = m->list; | |
| 207 | + else { | |
| 208 | + m = malloc(sizeof(Mnt)); | |
| 209 | + if(m == 0) { | |
| 210 | + unlock(&mntalloc.lk); | |
| 211 | + exhausted("mount devices"); | |
| 212 | + } | |
| 213 | + } | |
| 214 | + m->list = mntalloc.list; | |
| 215 | + mntalloc.list = m; | |
| 216 | + m->version = nil; | |
| 217 | + kstrdup(&m->version, f.version); | |
| 218 | + m->id = mntalloc.id++; | |
| 219 | + m->q = qopen(10*MAXRPC, 0, nil, nil); | |
| 220 | + m->msize = f.msize; | |
| 221 | + unlock(&mntalloc.lk); | |
| 222 | + | |
| 223 | + poperror(); /* msg */ | |
| 224 | + free(msg); | |
| 225 | + | |
| 226 | + lock(&m->lk); | |
| 227 | + m->queue = 0; | |
| 228 | + m->rip = 0; | |
| 229 | + | |
| 230 | + c->flag |= CMSG; | |
| 231 | + c->mux = m; | |
| 232 | + m->c = c; | |
| 233 | + unlock(&m->lk); | |
| 234 | + | |
| 235 | + poperror(); /* c */ | |
| 236 | + qunlock(&c->umqlock); | |
| 237 | + | |
| 238 | + k = strlen(f.version); | |
| 239 | + if(returnlen > 0){ | |
| 240 | + if(returnlen < k) | |
| 241 | + error(Eshort); | |
| 242 | + memmove(version, f.version, k); | |
| 243 | + } | |
| 244 | + | |
| 245 | + return k; | |
| 246 | +} | |
| 247 | + | |
| 248 | +Chan* | |
| 249 | +mntauth(Chan *c, char *spec) | |
| 250 | +{ | |
| 251 | + Mnt *m; | |
| 252 | + Mntrpc *r; | |
| 253 | + | |
| 254 | + m = c->mux; | |
| 255 | + | |
| 256 | + if(m == nil){ | |
| 257 | + mntversion(c, VERSION9P, MAXRPC, 0); | |
| 258 | + m = c->mux; | |
| 259 | + if(m == nil) | |
| 260 | + error(Enoversion); | |
| 261 | + } | |
| 262 | + | |
| 263 | + c = mntchan(); | |
| 264 | + if(waserror()) { | |
| 265 | + /* Close must not be called since it will | |
| 266 | + * call mnt recursively | |
| 267 | + */ | |
| 268 | + chanfree(c); | |
| 269 | + nexterror(); | |
| 270 | + } | |
| 271 | + | |
| 272 | + r = mntralloc(0, m->msize); | |
| 273 | + | |
| 274 | + if(waserror()) { | |
| 275 | + mntfree(r); | |
| 276 | + nexterror(); | |
| 277 | + } | |
| 278 | + | |
| 279 | + r->request.type = Tauth; | |
| 280 | + r->request.afid = c->fid; | |
| 281 | + r->request.uname = up->user; | |
| 282 | + r->request.aname = spec; | |
| 283 | + mountrpc(m, r); | |
| 284 | + | |
| 285 | + c->qid = r->reply.aqid; | |
| 286 | + c->mchan = m->c; | |
| 287 | + incref(&m->c->ref); | |
| 288 | + c->mqid = c->qid; | |
| 289 | + c->mode = ORDWR; | |
| 290 | + | |
| 291 | + poperror(); /* r */ | |
| 292 | + mntfree(r); | |
| 293 | + | |
| 294 | + poperror(); /* c */ | |
| 295 | + | |
| 296 | + return c; | |
| 297 | + | |
| 298 | +} | |
| 299 | + | |
| 300 | +static Chan* | |
| 301 | +mntattach(char *muxattach) | |
| 302 | +{ | |
| 303 | + Mnt *m; | |
| 304 | + Chan *c; | |
| 305 | + Mntrpc *r; | |
| 306 | + struct bogus{ | |
| 307 | + Chan *chan; | |
| 308 | + Chan *authchan; | |
| 309 | + char *spec; | |
| 310 | + int flags; | |
| 311 | + }bogus; | |
| 312 | + | |
| 313 | + bogus = *((struct bogus *)muxattach); | |
| 314 | + c = bogus.chan; | |
| 315 | + | |
| 316 | + m = c->mux; | |
| 317 | + | |
| 318 | + if(m == nil){ | |
| 319 | + mntversion(c, nil, 0, 0); | |
| 320 | + m = c->mux; | |
| 321 | + if(m == nil) | |
| 322 | + error(Enoversion); | |
| 323 | + } | |
| 324 | + | |
| 325 | + c = mntchan(); | |
| 326 | + if(waserror()) { | |
| 327 | + /* Close must not be called since it will | |
| 328 | + * call mnt recursively | |
| 329 | + */ | |
| 330 | + chanfree(c); | |
| 331 | + nexterror(); | |
| 332 | + } | |
| 333 | + | |
| 334 | + r = mntralloc(0, m->msize); | |
| 335 | + | |
| 336 | + if(waserror()) { | |
| 337 | + mntfree(r); | |
| 338 | + nexterror(); | |
| 339 | + } | |
| 340 | + | |
| 341 | + r->request.type = Tattach; | |
| 342 | + r->request.fid = c->fid; | |
| 343 | + if(bogus.authchan == nil) | |
| 344 | + r->request.afid = NOFID; | |
| 345 | + else | |
| 346 | + r->request.afid = bogus.authchan->fid; | |
| 347 | + r->request.uname = up->user; | |
| 348 | + r->request.aname = bogus.spec; | |
| 349 | + mountrpc(m, r); | |
| 350 | + | |
| 351 | + c->qid = r->reply.qid; | |
| 352 | + c->mchan = m->c; | |
| 353 | + incref(&m->c->ref); | |
| 354 | + c->mqid = c->qid; | |
| 355 | + | |
| 356 | + poperror(); /* r */ | |
| 357 | + mntfree(r); | |
| 358 | + | |
| 359 | + poperror(); /* c */ | |
| 360 | + | |
| 361 | + if(bogus.flags&MCACHE) | |
| 362 | + c->flag |= CCACHE; | |
| 363 | + return c; | |
| 364 | +} | |
| 365 | + | |
| 366 | +Chan* | |
| 367 | +mntchan(void) | |
| 368 | +{ | |
| 369 | + Chan *c; | |
| 370 | + | |
| 371 | + c = devattach('M', 0); | |
| 372 | + lock(&mntalloc.lk); | |
| 373 | + c->dev = mntalloc.id++; | |
| 374 | + unlock(&mntalloc.lk); | |
| 375 | + | |
| 376 | + if(c->mchan) | |
| 377 | + panic("mntchan non-zero %p", c->mchan); | |
| 378 | + return c; | |
| 379 | +} | |
| 380 | + | |
| 381 | +static Walkqid* | |
| 382 | +mntwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 383 | +{ | |
| 384 | + int i, alloc; | |
| 385 | + Mnt *m; | |
| 386 | + Mntrpc *r; | |
| 387 | + Walkqid *wq; | |
| 388 | + | |
| 389 | + if(nc != nil) | |
| 390 | + print("mntwalk: nc != nil\n"); | |
| 391 | + if(nname > MAXWELEM) | |
| 392 | + error("devmnt: too many name elements"); | |
| 393 | + alloc = 0; | |
| 394 | + wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); | |
| 395 | + if(waserror()){ | |
| 396 | + if(alloc && wq->clone!=nil) | |
| 397 | + cclose(wq->clone); | |
| 398 | + free(wq); | |
| 399 | + return nil; | |
| 400 | + } | |
| 401 | + | |
| 402 | + alloc = 0; | |
| 403 | + m = mntchk(c); | |
| 404 | + r = mntralloc(c, m->msize); | |
| 405 | + if(nc == nil){ | |
| 406 | + nc = devclone(c); | |
| 407 | + /* | |
| 408 | + * Until the other side accepts this fid, we can't mntclose it. | |
| 409 | + * Therefore set type to 0 for now; rootclose is known to be safe. | |
| 410 | + */ | |
| 411 | + nc->type = 0; | |
| 412 | + alloc = 1; | |
| 413 | + } | |
| 414 | + wq->clone = nc; | |
| 415 | + | |
| 416 | + if(waserror()) { | |
| 417 | + mntfree(r); | |
| 418 | + nexterror(); | |
| 419 | + } | |
| 420 | + r->request.type = Twalk; | |
| 421 | + r->request.fid = c->fid; | |
| 422 | + r->request.newfid = nc->fid; | |
| 423 | + r->request.nwname = nname; | |
| 424 | + memmove(r->request.wname, name, nname*sizeof(char*)); | |
| 425 | + | |
| 426 | + mountrpc(m, r); | |
| 427 | + | |
| 428 | + if(r->reply.nwqid > nname) | |
| 429 | + error("too many QIDs returned by walk"); | |
| 430 | + if(r->reply.nwqid < nname){ | |
| 431 | + if(alloc) | |
| 432 | + cclose(nc); | |
| 433 | + wq->clone = nil; | |
| 434 | + if(r->reply.nwqid == 0){ | |
| 435 | + free(wq); | |
| 436 | + wq = nil; | |
| 437 | + goto Return; | |
| 438 | + } | |
| 439 | + } | |
| 440 | + | |
| 441 | + /* move new fid onto mnt device and update its qid */ | |
| 442 | + if(wq->clone != nil){ | |
| 443 | + if(wq->clone != c){ | |
| 444 | + wq->clone->type = c->type; | |
| 445 | + wq->clone->mchan = c->mchan; | |
| 446 | + incref(&c->mchan->ref); | |
| 447 | + } | |
| 448 | + if(r->reply.nwqid > 0) | |
| 449 | + wq->clone->qid = r->reply.wqid[r->reply.nwqid-1]; | |
| 450 | + } | |
| 451 | + wq->nqid = r->reply.nwqid; | |
| 452 | + for(i=0; i<wq->nqid; i++) | |
| 453 | + wq->qid[i] = r->reply.wqid[i]; | |
| 454 | + | |
| 455 | + Return: | |
| 456 | + poperror(); | |
| 457 | + mntfree(r); | |
| 458 | + poperror(); | |
| 459 | + return wq; | |
| 460 | +} | |
| 461 | + | |
| 462 | +static int | |
| 463 | +mntstat(Chan *c, uchar *dp, int n) | |
| 464 | +{ | |
| 465 | + Mnt *m; | |
| 466 | + Mntrpc *r; | |
| 467 | + | |
| 468 | + if(n < BIT16SZ) | |
| 469 | + error(Eshortstat); | |
| 470 | + m = mntchk(c); | |
| 471 | + r = mntralloc(c, m->msize); | |
| 472 | + if(waserror()) { | |
| 473 | + mntfree(r); | |
| 474 | + nexterror(); | |
| 475 | + } | |
| 476 | + r->request.type = Tstat; | |
| 477 | + r->request.fid = c->fid; | |
| 478 | + mountrpc(m, r); | |
| 479 | + | |
| 480 | + if(r->reply.nstat >= 1<<(8*BIT16SZ)) | |
| 481 | + error("returned stat buffer count too large"); | |
| 482 | + | |
| 483 | + if(r->reply.nstat > n){ | |
| 484 | + /* | |
| 485 | + * 12/31/2002 RSC | |
| 486 | + * | |
| 487 | + * This should be nstat-2, which is the first two | |
| 488 | + * bytes of the stat buffer. But dirstat and dirfstat | |
| 489 | + * depended on getting the full nstat (they didn't | |
| 490 | + * add BIT16SZ themselves). I fixed dirstat and dirfstat | |
| 491 | + * but am leaving this unchanged for now. After a | |
| 492 | + * few months, once enough of the relevant binaries | |
| 493 | + * have been recompiled for other reasons, we can | |
| 494 | + * change this to nstat-2. Devstat gets this right | |
| 495 | + * (via convD2M). | |
| 496 | + */ | |
| 497 | + /* doesn't fit; just patch the count and return */ | |
| 498 | + PBIT16((uchar*)dp, r->reply.nstat); | |
| 499 | + n = BIT16SZ; | |
| 500 | + }else{ | |
| 501 | + n = r->reply.nstat; | |
| 502 | + memmove(dp, r->reply.stat, n); | |
| 503 | + validstat(dp, n); | |
| 504 | + mntdirfix(dp, c); | |
| 505 | + } | |
| 506 | + poperror(); | |
| 507 | + mntfree(r); | |
| 508 | + return n; | |
| 509 | +} | |
| 510 | + | |
| 511 | +static Chan* | |
| 512 | +mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) | |
| 513 | +{ | |
| 514 | + Mnt *m; | |
| 515 | + Mntrpc *r; | |
| 516 | + | |
| 517 | + m = mntchk(c); | |
| 518 | + r = mntralloc(c, m->msize); | |
| 519 | + if(waserror()) { | |
| 520 | + mntfree(r); | |
| 521 | + nexterror(); | |
| 522 | + } | |
| 523 | + r->request.type = type; | |
| 524 | + r->request.fid = c->fid; | |
| 525 | + r->request.mode = omode; | |
| 526 | + if(type == Tcreate){ | |
| 527 | + r->request.perm = perm; | |
| 528 | + r->request.name = name; | |
| 529 | + } | |
| 530 | + mountrpc(m, r); | |
| 531 | + | |
| 532 | + c->qid = r->reply.qid; | |
| 533 | + c->offset = 0; | |
| 534 | + c->mode = openmode(omode); | |
| 535 | + c->iounit = r->reply.iounit; | |
| 536 | + if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ) | |
| 537 | + c->iounit = m->msize-IOHDRSZ; | |
| 538 | + c->flag |= COPEN; | |
| 539 | + poperror(); | |
| 540 | + mntfree(r); | |
| 541 | + | |
| 542 | + if(c->flag & CCACHE) | |
| 543 | + copen(c); | |
| 544 | + | |
| 545 | + return c; | |
| 546 | +} | |
| 547 | + | |
| 548 | +static Chan* | |
| 549 | +mntopen(Chan *c, int omode) | |
| 550 | +{ | |
| 551 | + return mntopencreate(Topen, c, nil, omode, 0); | |
| 552 | +} | |
| 553 | + | |
| 554 | +static void | |
| 555 | +mntcreate(Chan *c, char *name, int omode, ulong perm) | |
| 556 | +{ | |
| 557 | + mntopencreate(Tcreate, c, name, omode, perm); | |
| 558 | +} | |
| 559 | + | |
| 560 | +static void | |
| 561 | +mntclunk(Chan *c, int t) | |
| 562 | +{ | |
| 563 | + Mnt *m; | |
| 564 | + Mntrpc *r; | |
| 565 | + | |
| 566 | + m = mntchk(c); | |
| 567 | + r = mntralloc(c, m->msize); | |
| 568 | + if(waserror()){ | |
| 569 | + mntfree(r); | |
| 570 | + nexterror(); | |
| 571 | + } | |
| 572 | + | |
| 573 | + r->request.type = t; | |
| 574 | + r->request.fid = c->fid; | |
| 575 | + mountrpc(m, r); | |
| 576 | + mntfree(r); | |
| 577 | + poperror(); | |
| 578 | +} | |
| 579 | + | |
| 580 | +void | |
| 581 | +muxclose(Mnt *m) | |
| 582 | +{ | |
| 583 | + Mntrpc *q, *r; | |
| 584 | + | |
| 585 | + for(q = m->queue; q; q = r) { | |
| 586 | + r = q->list; | |
| 587 | + mntfree(q); | |
| 588 | + } | |
| 589 | + m->id = 0; | |
| 590 | + free(m->version); | |
| 591 | + m->version = nil; | |
| 592 | + mntpntfree(m); | |
| 593 | +} | |
| 594 | + | |
| 595 | +void | |
| 596 | +mntpntfree(Mnt *m) | |
| 597 | +{ | |
| 598 | + Mnt *f, **l; | |
| 599 | + Queue *q; | |
| 600 | + | |
| 601 | + lock(&mntalloc.lk); | |
| 602 | + l = &mntalloc.list; | |
| 603 | + for(f = *l; f; f = f->list) { | |
| 604 | + if(f == m) { | |
| 605 | + *l = m->list; | |
| 606 | + break; | |
| 607 | + } | |
| 608 | + l = &f->list; | |
| 609 | + } | |
| 610 | + m->list = mntalloc.mntfree; | |
| 611 | + mntalloc.mntfree = m; | |
| 612 | + q = m->q; | |
| 613 | + unlock(&mntalloc.lk); | |
| 614 | + | |
| 615 | + qfree(q); | |
| 616 | +} | |
| 617 | + | |
| 618 | +static void | |
| 619 | +mntclose(Chan *c) | |
| 620 | +{ | |
| 621 | + mntclunk(c, Tclunk); | |
| 622 | +} | |
| 623 | + | |
| 624 | +static void | |
| 625 | +mntremove(Chan *c) | |
| 626 | +{ | |
| 627 | + mntclunk(c, Tremove); | |
| 628 | +} | |
| 629 | + | |
| 630 | +static int | |
| 631 | +mntwstat(Chan *c, uchar *dp, int n) | |
| 632 | +{ | |
| 633 | + Mnt *m; | |
| 634 | + Mntrpc *r; | |
| 635 | + | |
| 636 | + m = mntchk(c); | |
| 637 | + r = mntralloc(c, m->msize); | |
| 638 | + if(waserror()) { | |
| 639 | + mntfree(r); | |
| 640 | + nexterror(); | |
| 641 | + } | |
| 642 | + r->request.type = Twstat; | |
| 643 | + r->request.fid = c->fid; | |
| 644 | + r->request.nstat = n; | |
| 645 | + r->request.stat = dp; | |
| 646 | + mountrpc(m, r); | |
| 647 | + poperror(); | |
| 648 | + mntfree(r); | |
| 649 | + return n; | |
| 650 | +} | |
| 651 | + | |
| 652 | +static long | |
| 653 | +mntread(Chan *c, void *buf, long n, vlong off) | |
| 654 | +{ | |
| 655 | + uchar *p, *e; | |
| 656 | + int nc, cache, isdir, dirlen; | |
| 657 | + | |
| 658 | + isdir = 0; | |
| 659 | + cache = c->flag & CCACHE; | |
| 660 | + if(c->qid.type & QTDIR) { | |
| 661 | + cache = 0; | |
| 662 | + isdir = 1; | |
| 663 | + } | |
| 664 | + | |
| 665 | + p = buf; | |
| 666 | + if(cache) { | |
| 667 | + nc = cread(c, buf, n, off); | |
| 668 | + if(nc > 0) { | |
| 669 | + n -= nc; | |
| 670 | + if(n == 0) | |
| 671 | + return nc; | |
| 672 | + p += nc; | |
| 673 | + off += nc; | |
| 674 | + } | |
| 675 | + n = mntrdwr(Tread, c, p, n, off); | |
| 676 | + cupdate(c, p, n, off); | |
| 677 | + return n + nc; | |
| 678 | + } | |
| 679 | + | |
| 680 | + n = mntrdwr(Tread, c, buf, n, off); | |
| 681 | + if(isdir) { | |
| 682 | + for(e = &p[n]; p+BIT16SZ < e; p += dirlen){ | |
| 683 | + dirlen = BIT16SZ+GBIT16(p); | |
| 684 | + if(p+dirlen > e) | |
| 685 | + break; | |
| 686 | + validstat(p, dirlen); | |
| 687 | + mntdirfix(p, c); | |
| 688 | + } | |
| 689 | + if(p != e) | |
| 690 | + error(Esbadstat); | |
| 691 | + } | |
| 692 | + return n; | |
| 693 | +} | |
| 694 | + | |
| 695 | +static long | |
| 696 | +mntwrite(Chan *c, void *buf, long n, vlong off) | |
| 697 | +{ | |
| 698 | + return mntrdwr(Twrite, c, buf, n, off); | |
| 699 | +} | |
| 700 | + | |
| 701 | +long | |
| 702 | +mntrdwr(int type, Chan *c, void *buf, long n, vlong off) | |
| 703 | +{ | |
| 704 | + Mnt *m; | |
| 705 | + Mntrpc *r; | |
| 706 | + char *uba; | |
| 707 | + int cache; | |
| 708 | + ulong cnt, nr, nreq; | |
| 709 | + | |
| 710 | + m = mntchk(c); | |
| 711 | + uba = buf; | |
| 712 | + cnt = 0; | |
| 713 | + cache = c->flag & CCACHE; | |
| 714 | + if(c->qid.type & QTDIR) | |
| 715 | + cache = 0; | |
| 716 | + for(;;) { | |
| 717 | + r = mntralloc(c, m->msize); | |
| 718 | + if(waserror()) { | |
| 719 | + mntfree(r); | |
| 720 | + nexterror(); | |
| 721 | + } | |
| 722 | + r->request.type = type; | |
| 723 | + r->request.fid = c->fid; | |
| 724 | + r->request.offset = off; | |
| 725 | + r->request.data = uba; | |
| 726 | + nr = n; | |
| 727 | + if(nr > m->msize-IOHDRSZ) | |
| 728 | + nr = m->msize-IOHDRSZ; | |
| 729 | + r->request.count = nr; | |
| 730 | + mountrpc(m, r); | |
| 731 | + nreq = r->request.count; | |
| 732 | + nr = r->reply.count; | |
| 733 | + if(nr > nreq) | |
| 734 | + nr = nreq; | |
| 735 | + | |
| 736 | + if(type == Tread) | |
| 737 | + r->b = bl2mem((uchar*)uba, r->b, nr); | |
| 738 | + else if(cache) | |
| 739 | + cwrite(c, (uchar*)uba, nr, off); | |
| 740 | + | |
| 741 | + poperror(); | |
| 742 | + mntfree(r); | |
| 743 | + off += nr; | |
| 744 | + uba += nr; | |
| 745 | + cnt += nr; | |
| 746 | + n -= nr; | |
| 747 | + if(nr != nreq || n == 0) | |
| 748 | + break; | |
| 749 | + } | |
| 750 | + return cnt; | |
| 751 | +} | |
| 752 | + | |
| 753 | +void | |
| 754 | +mountrpc(Mnt *m, Mntrpc *r) | |
| 755 | +{ | |
| 756 | + char *sn, *cn; | |
| 757 | + int t; | |
| 758 | + | |
| 759 | + r->reply.tag = 0; | |
| 760 | + r->reply.type = Tmax; /* can't ever be a valid message type */ | |
| 761 | + | |
| 762 | + mountio(m, r); | |
| 763 | + | |
| 764 | + t = r->reply.type; | |
| 765 | + switch(t) { | |
| 766 | + case Rerror: | |
| 767 | + error(r->reply.ename); | |
| 768 | + case Rflush: | |
| 769 | + error(Eintr); | |
| 770 | + default: | |
| 771 | + if(t == r->request.type+1) | |
| 772 | + break; | |
| 773 | + sn = "?"; | |
| 774 | + if(m->c->name != nil) | |
| 775 | + sn = m->c->name->s; | |
| 776 | + cn = "?"; | |
| 777 | + if(r->c != nil && r->c->name != nil) | |
| 778 | + cn = r->c->name->s; | |
| 779 | + print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n", | |
| 780 | + up->pid, sn, cn, | |
| 781 | + r, r->request.tag, r->request.fid, r->request.type, | |
| 782 | + r->reply.type, r->reply.tag); | |
| 783 | + error(Emountrpc); | |
| 784 | + } | |
| 785 | +} | |
| 786 | + | |
| 787 | +void | |
| 788 | +mountio(Mnt *m, Mntrpc *r) | |
| 789 | +{ | |
| 790 | + int n; | |
| 791 | + | |
| 792 | + while(waserror()) { | |
| 793 | + if(m->rip == up) | |
| 794 | + mntgate(m); | |
| 795 | + if(strcmp(up->errstr, Eintr) != 0){ | |
| 796 | + mntflushfree(m, r); | |
| 797 | + nexterror(); | |
| 798 | + } | |
| 799 | + r = mntflushalloc(r, m->msize); | |
| 800 | + } | |
| 801 | + | |
| 802 | + lock(&m->lk); | |
| 803 | + r->m = m; | |
| 804 | + r->list = m->queue; | |
| 805 | + m->queue = r; | |
| 806 | + unlock(&m->lk); | |
| 807 | + | |
| 808 | + /* Transmit a file system rpc */ | |
| 809 | + if(m->msize == 0) | |
| 810 | + panic("msize"); | |
| 811 | + n = convS2M(&r->request, r->rpc, m->msize); | |
| 812 | + if(n < 0) | |
| 813 | + panic("bad message type in mountio"); | |
| 814 | + if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) | |
| 815 | + error(Emountrpc); | |
| 816 | + r->stime = fastticks(nil); | |
| 817 | + r->reqlen = n; | |
| 818 | + | |
| 819 | + /* Gate readers onto the mount point one at a time */ | |
| 820 | + for(;;) { | |
| 821 | + lock(&m->lk); | |
| 822 | + if(m->rip == 0) | |
| 823 | + break; | |
| 824 | + unlock(&m->lk); | |
| 825 | + sleep(&r->r, rpcattn, r); | |
| 826 | + if(r->done){ | |
| 827 | + poperror(); | |
| 828 | + mntflushfree(m, r); | |
| 829 | + return; | |
| 830 | + } | |
| 831 | + } | |
| 832 | + m->rip = up; | |
| 833 | + unlock(&m->lk); | |
| 834 | + while(r->done == 0) { | |
| 835 | + if(mntrpcread(m, r) < 0) | |
| 836 | + error(Emountrpc); | |
| 837 | + mountmux(m, r); | |
| 838 | + } | |
| 839 | + mntgate(m); | |
| 840 | + poperror(); | |
| 841 | + mntflushfree(m, r); | |
| 842 | +} | |
| 843 | + | |
| 844 | +static int | |
| 845 | +doread(Mnt *m, int len) | |
| 846 | +{ | |
| 847 | + Block *b; | |
| 848 | + | |
| 849 | + while(qlen(m->q) < len){ | |
| 850 | + b = devtab[m->c->type]->bread(m->c, m->msize, 0); | |
| 851 | + if(b == nil) | |
| 852 | + return -1; | |
| 853 | + if(BLEN(b) == 0){ | |
| 854 | + freeblist(b); | |
| 855 | + return -1; | |
| 856 | + } | |
| 857 | + qaddlist(m->q, b); | |
| 858 | + } | |
| 859 | + return 0; | |
| 860 | +} | |
| 861 | + | |
| 862 | +int | |
| 863 | +mntrpcread(Mnt *m, Mntrpc *r) | |
| 864 | +{ | |
| 865 | + int i, t, len, hlen; | |
| 866 | + Block *b, **l, *nb; | |
| 867 | + | |
| 868 | + r->reply.type = 0; | |
| 869 | + r->reply.tag = 0; | |
| 870 | + | |
| 871 | + /* read at least length, type, and tag and pullup to a single block */ | |
| 872 | + if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0) | |
| 873 | + return -1; | |
| 874 | + nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ); | |
| 875 | + | |
| 876 | + /* read in the rest of the message, avoid rediculous (for now) message sizes */ | |
| 877 | + len = GBIT32(nb->rp); | |
| 878 | + if(len > m->msize){ | |
| 879 | + qdiscard(m->q, qlen(m->q)); | |
| 880 | + return -1; | |
| 881 | + } | |
| 882 | + if(doread(m, len) < 0) | |
| 883 | + return -1; | |
| 884 | + | |
| 885 | + /* pullup the header (i.e. everything except data) */ | |
| 886 | + t = nb->rp[BIT32SZ]; | |
| 887 | + switch(t){ | |
| 888 | + case Rread: | |
| 889 | + hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ; | |
| 890 | + break; | |
| 891 | + default: | |
| 892 | + hlen = len; | |
| 893 | + break; | |
| 894 | + } | |
| 895 | + nb = pullupqueue(m->q, hlen); | |
| 896 | + | |
| 897 | + if(convM2S(nb->rp, len, &r->reply) <= 0){ | |
| 898 | + /* bad message, dump it */ | |
| 899 | + print("mntrpcread: convM2S failed\n"); | |
| 900 | + qdiscard(m->q, len); | |
| 901 | + return -1; | |
| 902 | + } | |
| 903 | + | |
| 904 | + /* hang the data off of the fcall struct */ | |
| 905 | + l = &r->b; | |
| 906 | + *l = nil; | |
| 907 | + do { | |
| 908 | + b = qremove(m->q); | |
| 909 | + if(hlen > 0){ | |
| 910 | + b->rp += hlen; | |
| 911 | + len -= hlen; | |
| 912 | + hlen = 0; | |
| 913 | + } | |
| 914 | + i = BLEN(b); | |
| 915 | + if(i <= len){ | |
| 916 | + len -= i; | |
| 917 | + *l = b; | |
| 918 | + l = &(b->next); | |
| 919 | + } else { | |
| 920 | + /* split block and put unused bit back */ | |
| 921 | + nb = allocb(i-len); | |
| 922 | + memmove(nb->wp, b->rp+len, i-len); | |
| 923 | + b->wp = b->rp+len; | |
| 924 | + nb->wp += i-len; | |
| 925 | + qputback(m->q, nb); | |
| 926 | + *l = b; | |
| 927 | + return 0; | |
| 928 | + } | |
| 929 | + }while(len > 0); | |
| 930 | + | |
| 931 | + return 0; | |
| 932 | +} | |
| 933 | + | |
| 934 | +void | |
| 935 | +mntgate(Mnt *m) | |
| 936 | +{ | |
| 937 | + Mntrpc *q; | |
| 938 | + | |
| 939 | + lock(&m->lk); | |
| 940 | + m->rip = 0; | |
| 941 | + for(q = m->queue; q; q = q->list) { | |
| 942 | + if(q->done == 0) | |
| 943 | + if(wakeup(&q->r)) | |
| 944 | + break; | |
| 945 | + } | |
| 946 | + unlock(&m->lk); | |
| 947 | +} | |
| 948 | + | |
| 949 | +void | |
| 950 | +mountmux(Mnt *m, Mntrpc *r) | |
| 951 | +{ | |
| 952 | + Mntrpc **l, *q; | |
| 953 | + | |
| 954 | + lock(&m->lk); | |
| 955 | + l = &m->queue; | |
| 956 | + for(q = *l; q; q = q->list) { | |
| 957 | + /* look for a reply to a message */ | |
| 958 | + if(q->request.tag == r->reply.tag) { | |
| 959 | + *l = q->list; | |
| 960 | + if(q != r) { | |
| 961 | + /* | |
| 962 | + * Completed someone else. | |
| 963 | + * Trade pointers to receive buffer. | |
| 964 | + */ | |
| 965 | + q->reply = r->reply; | |
| 966 | + q->b = r->b; | |
| 967 | + r->b = nil; | |
| 968 | + } | |
| 969 | + q->done = 1; | |
| 970 | + unlock(&m->lk); | |
| 971 | + if(mntstats != nil) | |
| 972 | + (*mntstats)(q->request.type, | |
| 973 | + m->c, q->stime, | |
| 974 | + q->reqlen + r->replen); | |
| 975 | + if(q != r) | |
| 976 | + wakeup(&q->r); | |
| 977 | + return; | |
| 978 | + } | |
| 979 | + l = &q->list; | |
| 980 | + } | |
| 981 | + unlock(&m->lk); | |
| 982 | + print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type); | |
| 983 | +} | |
| 984 | + | |
| 985 | +/* | |
| 986 | + * Create a new flush request and chain the previous | |
| 987 | + * requests from it | |
| 988 | + */ | |
| 989 | +Mntrpc* | |
| 990 | +mntflushalloc(Mntrpc *r, ulong iounit) | |
| 991 | +{ | |
| 992 | + Mntrpc *fr; | |
| 993 | + | |
| 994 | + fr = mntralloc(0, iounit); | |
| 995 | + | |
| 996 | + fr->request.type = Tflush; | |
| 997 | + if(r->request.type == Tflush) | |
| 998 | + fr->request.oldtag = r->request.oldtag; | |
| 999 | + else | |
| 1000 | + fr->request.oldtag = r->request.tag; | |
| 1001 | + fr->flushed = r; | |
| 1002 | + | |
| 1003 | + return fr; | |
| 1004 | +} | |
| 1005 | + | |
| 1006 | +/* | |
| 1007 | + * Free a chain of flushes. Remove each unanswered | |
| 1008 | + * flush and the original message from the unanswered | |
| 1009 | + * request queue. Mark the original message as done | |
| 1010 | + * and if it hasn't been answered set the reply to to | |
| 1011 | + * Rflush. | |
| 1012 | + */ | |
| 1013 | +void | |
| 1014 | +mntflushfree(Mnt *m, Mntrpc *r) | |
| 1015 | +{ | |
| 1016 | + Mntrpc *fr; | |
| 1017 | + | |
| 1018 | + while(r){ | |
| 1019 | + fr = r->flushed; | |
| 1020 | + if(!r->done){ | |
| 1021 | + r->reply.type = Rflush; | |
| 1022 | + mntqrm(m, r); | |
| 1023 | + } | |
| 1024 | + if(fr) | |
| 1025 | + mntfree(r); | |
| 1026 | + r = fr; | |
| 1027 | + } | |
| 1028 | +} | |
| 1029 | + | |
| 1030 | +int | |
| 1031 | +alloctag(void) | |
| 1032 | +{ | |
| 1033 | + int i, j; | |
| 1034 | + ulong v; | |
| 1035 | + | |
| 1036 | + for(i = 0; i < NMASK; i++){ | |
| 1037 | + v = mntalloc.tagmask[i]; | |
| 1038 | + if(v == ~0UL) | |
| 1039 | + continue; | |
| 1040 | + for(j = 0; j < 1<<TAGSHIFT; j++) | |
| 1041 | + if((v & (1<<j)) == 0){ | |
| 1042 | + mntalloc.tagmask[i] |= 1<<j; | |
| 1043 | + return (i<<TAGSHIFT) + j; | |
| 1044 | + } | |
| 1045 | + } | |
| 1046 | + panic("no friggin tags left"); | |
| 1047 | + return NOTAG; | |
| 1048 | +} | |
| 1049 | + | |
| 1050 | +void | |
| 1051 | +freetag(int t) | |
| 1052 | +{ | |
| 1053 | + mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK)); | |
| 1054 | +} | |
| 1055 | + | |
| 1056 | +Mntrpc* | |
| 1057 | +mntralloc(Chan *c, ulong msize) | |
| 1058 | +{ | |
| 1059 | + Mntrpc *new; | |
| 1060 | + | |
| 1061 | + lock(&mntalloc.lk); | |
| 1062 | + new = mntalloc.rpcfree; | |
| 1063 | + if(new == nil){ | |
| 1064 | + new = malloc(sizeof(Mntrpc)); | |
| 1065 | + if(new == nil) { | |
| 1066 | + unlock(&mntalloc.lk); | |
| 1067 | + exhausted("mount rpc header"); | |
| 1068 | + } | |
| 1069 | + /* | |
| 1070 | + * The header is split from the data buffer as | |
| 1071 | + * mountmux may swap the buffer with another header. | |
| 1072 | + */ | |
| 1073 | + new->rpc = mallocz(msize, 0); | |
| 1074 | + if(new->rpc == nil){ | |
| 1075 | + free(new); | |
| 1076 | + unlock(&mntalloc.lk); | |
| 1077 | + exhausted("mount rpc buffer"); | |
| 1078 | + } | |
| 1079 | + new->rpclen = msize; | |
| 1080 | + new->request.tag = alloctag(); | |
| 1081 | + } | |
| 1082 | + else { | |
| 1083 | + mntalloc.rpcfree = new->list; | |
| 1084 | + mntalloc.nrpcfree--; | |
| 1085 | + if(new->rpclen < msize){ | |
| 1086 | + free(new->rpc); | |
| 1087 | + new->rpc = mallocz(msize, 0); | |
| 1088 | + if(new->rpc == nil){ | |
| 1089 | + free(new); | |
| 1090 | + mntalloc.nrpcused--; | |
| 1091 | + unlock(&mntalloc.lk); | |
| 1092 | + exhausted("mount rpc buffer"); | |
| 1093 | + } | |
| 1094 | + new->rpclen = msize; | |
| 1095 | + } | |
| 1096 | + } | |
| 1097 | + mntalloc.nrpcused++; | |
| 1098 | + unlock(&mntalloc.lk); | |
| 1099 | + new->c = c; | |
| 1100 | + new->done = 0; | |
| 1101 | + new->flushed = nil; | |
| 1102 | + new->b = nil; | |
| 1103 | + return new; | |
| 1104 | +} | |
| 1105 | + | |
| 1106 | +void | |
| 1107 | +mntfree(Mntrpc *r) | |
| 1108 | +{ | |
| 1109 | + if(r->b != nil) | |
| 1110 | + freeblist(r->b); | |
| 1111 | + lock(&mntalloc.lk); | |
| 1112 | + if(mntalloc.nrpcfree >= 10){ | |
| 1113 | + free(r->rpc); | |
| 1114 | + free(r); | |
| 1115 | + freetag(r->request.tag); | |
| 1116 | + } | |
| 1117 | + else{ | |
| 1118 | + r->list = mntalloc.rpcfree; | |
| 1119 | + mntalloc.rpcfree = r; | |
| 1120 | + mntalloc.nrpcfree++; | |
| 1121 | + } | |
| 1122 | + mntalloc.nrpcused--; | |
| 1123 | + unlock(&mntalloc.lk); | |
| 1124 | +} | |
| 1125 | + | |
| 1126 | +void | |
| 1127 | +mntqrm(Mnt *m, Mntrpc *r) | |
| 1128 | +{ | |
| 1129 | + Mntrpc **l, *f; | |
| 1130 | + | |
| 1131 | + lock(&m->lk); | |
| 1132 | + r->done = 1; | |
| 1133 | + | |
| 1134 | + l = &m->queue; | |
| 1135 | + for(f = *l; f; f = f->list) { | |
| 1136 | + if(f == r) { | |
| 1137 | + *l = r->list; | |
| 1138 | + break; | |
| 1139 | + } | |
| 1140 | + l = &f->list; | |
| 1141 | + } | |
| 1142 | + unlock(&m->lk); | |
| 1143 | +} | |
| 1144 | + | |
| 1145 | +Mnt* | |
| 1146 | +mntchk(Chan *c) | |
| 1147 | +{ | |
| 1148 | + Mnt *m; | |
| 1149 | + | |
| 1150 | + /* This routine is mostly vestiges of prior lives; now it's just sanity checking */ | |
| 1151 | + | |
| 1152 | + if(c->mchan == nil) | |
| 1153 | + panic("mntchk 1: nil mchan c %s\n", c2name(c)); | |
| 1154 | + | |
| 1155 | + m = c->mchan->mux; | |
| 1156 | + | |
| 1157 | + if(m == nil) | |
| 1158 | + print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan)); | |
| 1159 | + | |
| 1160 | + /* | |
| 1161 | + * Was it closed and reused (was error(Eshutdown); now, it can't happen) | |
| 1162 | + */ | |
| 1163 | + if(m->id == 0 || m->id >= c->dev) | |
| 1164 | + panic("mntchk 3: can't happen"); | |
| 1165 | + | |
| 1166 | + return m; | |
| 1167 | +} | |
| 1168 | + | |
| 1169 | +/* | |
| 1170 | + * Rewrite channel type and dev for in-flight data to | |
| 1171 | + * reflect local values. These entries are known to be | |
| 1172 | + * the first two in the Dir encoding after the count. | |
| 1173 | + */ | |
| 1174 | +void | |
| 1175 | +mntdirfix(uchar *dirbuf, Chan *c) | |
| 1176 | +{ | |
| 1177 | + uint r; | |
| 1178 | + | |
| 1179 | + r = devtab[c->type]->dc; | |
| 1180 | + dirbuf += BIT16SZ; /* skip count */ | |
| 1181 | + PBIT16(dirbuf, r); | |
| 1182 | + dirbuf += BIT16SZ; | |
| 1183 | + PBIT32(dirbuf, c->dev); | |
| 1184 | +} | |
| 1185 | + | |
| 1186 | +int | |
| 1187 | +rpcattn(void *v) | |
| 1188 | +{ | |
| 1189 | + Mntrpc *r; | |
| 1190 | + | |
| 1191 | + r = v; | |
| 1192 | + return r->done || r->m->rip == 0; | |
| 1193 | +} | |
| 1194 | + | |
| 1195 | +Dev mntdevtab = { | |
| 1196 | + 'M', | |
| 1197 | + "mnt", | |
| 1198 | + | |
| 1199 | + mntreset, | |
| 1200 | + devinit, | |
| 1201 | + devshutdown, | |
| 1202 | + mntattach, | |
| 1203 | + mntwalk, | |
| 1204 | + mntstat, | |
| 1205 | + mntopen, | |
| 1206 | + mntcreate, | |
| 1207 | + mntclose, | |
| 1208 | + mntread, | |
| 1209 | + devbread, | |
| 1210 | + mntwrite, | |
| 1211 | + devbwrite, | |
| 1212 | + mntremove, | |
| 1213 | + mntwstat, | |
| 1214 | +}; | |
| @@ -0,0 +1,237 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#include "draw.h" | |
| 8 | +#include "memdraw.h" | |
| 9 | +#include "screen.h" | |
| 10 | + | |
| 11 | +int mousequeue; | |
| 12 | + | |
| 13 | +Mouseinfo mouse; | |
| 14 | +Cursorinfo cursor; | |
| 15 | + | |
| 16 | +static int mousechanged(void*); | |
| 17 | + | |
| 18 | +enum{ | |
| 19 | + Qdir, | |
| 20 | + Qcursor, | |
| 21 | + Qmouse | |
| 22 | +}; | |
| 23 | + | |
| 24 | +Dirtab mousedir[]={ | |
| 25 | + ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, | |
| 26 | + "cursor", {Qcursor}, 0, 0666, | |
| 27 | + "mouse", {Qmouse}, 0, 0666, | |
| 28 | +}; | |
| 29 | + | |
| 30 | +#define NMOUSE (sizeof(mousedir)/sizeof(Dirtab)) | |
| 31 | + | |
| 32 | +static Chan* | |
| 33 | +mouseattach(char *spec) | |
| 34 | +{ | |
| 35 | + return devattach('m', spec); | |
| 36 | +} | |
| 37 | + | |
| 38 | +static Walkqid* | |
| 39 | +mousewalk(Chan *c, Chan *nc, char **name, int nname) | |
| 40 | +{ | |
| 41 | + return devwalk(c, nc, name, nname, mousedir, NMOUSE, devgen); | |
| 42 | +} | |
| 43 | + | |
| 44 | +static int | |
| 45 | +mousestat(Chan *c, uchar *db, int n) | |
| 46 | +{ | |
| 47 | + return devstat(c, db, n, mousedir, NMOUSE, devgen); | |
| 48 | +} | |
| 49 | + | |
| 50 | +static Chan* | |
| 51 | +mouseopen(Chan *c, int omode) | |
| 52 | +{ | |
| 53 | + switch((long)c->qid.path){ | |
| 54 | + case Qdir: | |
| 55 | + if(omode != OREAD) | |
| 56 | + error(Eperm); | |
| 57 | + break; | |
| 58 | + case Qmouse: | |
| 59 | + lock(&mouse.lk); | |
| 60 | + if(mouse.open){ | |
| 61 | + unlock(&mouse.lk); | |
| 62 | + error(Einuse); | |
| 63 | + } | |
| 64 | + mouse.open = 1; | |
| 65 | + unlock(&mouse.lk); | |
| 66 | + break; | |
| 67 | + } | |
| 68 | + c->mode = openmode(omode); | |
| 69 | + c->flag |= COPEN; | |
| 70 | + c->offset = 0; | |
| 71 | + return c; | |
| 72 | +} | |
| 73 | + | |
| 74 | +void | |
| 75 | +mouseclose(Chan *c) | |
| 76 | +{ | |
| 77 | + if(!(c->flag&COPEN)) | |
| 78 | + return; | |
| 79 | + | |
| 80 | + switch((long)c->qid.path) { | |
| 81 | + case Qmouse: | |
| 82 | + lock(&mouse.lk); | |
| 83 | + mouse.open = 0; | |
| 84 | + unlock(&mouse.lk); | |
| 85 | + cursorarrow(); | |
| 86 | + } | |
| 87 | +} | |
| 88 | + | |
| 89 | + | |
| 90 | +long | |
| 91 | +mouseread(Chan *c, void *va, long n, vlong offset) | |
| 92 | +{ | |
| 93 | + char buf[4*12+1]; | |
| 94 | + uchar *p; | |
| 95 | + int i, nn; | |
| 96 | + ulong msec; | |
| 97 | +/* static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; */ | |
| 98 | + | |
| 99 | + p = va; | |
| 100 | + switch((long)c->qid.path){ | |
| 101 | + case Qdir: | |
| 102 | + return devdirread(c, va, n, mousedir, NMOUSE, devgen); | |
| 103 | + | |
| 104 | + case Qcursor: | |
| 105 | + if(offset != 0) | |
| 106 | + return 0; | |
| 107 | + if(n < 2*4+2*2*16) | |
| 108 | + error(Eshort); | |
| 109 | + n = 2*4+2*2*16; | |
| 110 | + lock(&cursor.lk); | |
| 111 | + BPLONG(p+0, cursor.offset.x); | |
| 112 | + BPLONG(p+4, cursor.offset.y); | |
| 113 | + memmove(p+8, cursor.clr, 2*16); | |
| 114 | + memmove(p+40, cursor.set, 2*16); | |
| 115 | + unlock(&cursor.lk); | |
| 116 | + return n; | |
| 117 | + | |
| 118 | + case Qmouse: | |
| 119 | + while(mousechanged(0) == 0) | |
| 120 | + sleep(&mouse.r, mousechanged, 0); | |
| 121 | + | |
| 122 | + lock(&screen.lk); | |
| 123 | + if(screen.reshaped) { | |
| 124 | + screen.reshaped = 0; | |
| 125 | + sprint(buf, "t%11d %11d", 0, ticks()); | |
| 126 | + if(n > 1+2*12) | |
| 127 | + n = 1+2*12; | |
| 128 | + memmove(va, buf, n); | |
| 129 | + unlock(&screen.lk); | |
| 130 | + return n; | |
| 131 | + } | |
| 132 | + unlock(&screen.lk); | |
| 133 | + | |
| 134 | + lock(&mouse.lk); | |
| 135 | + i = mouse.ri; | |
| 136 | + nn = (mouse.wi + Mousequeue - i) % Mousequeue; | |
| 137 | + if(nn < 1) | |
| 138 | + panic("empty mouse queue"); | |
| 139 | + msec = ticks(); | |
| 140 | + while(nn > 1) { | |
| 141 | + if(mouse.queue[i].msec + Mousewindow > msec) | |
| 142 | + break; | |
| 143 | + i = (i+1)%Mousequeue; | |
| 144 | + nn--; | |
| 145 | + } | |
| 146 | + sprint(buf, "m%11d %11d %11d %11d", | |
| 147 | + mouse.queue[i].xy.x, | |
| 148 | + mouse.queue[i].xy.y, | |
| 149 | + mouse.queue[i].buttons, | |
| 150 | + mouse.queue[i].msec); | |
| 151 | + mouse.ri = (i+1)%Mousequeue; | |
| 152 | + unlock(&mouse.lk); | |
| 153 | + if(n > 1+4*12) | |
| 154 | + n = 1+4*12; | |
| 155 | + memmove(va, buf, n); | |
| 156 | + return n; | |
| 157 | + } | |
| 158 | + return 0; | |
| 159 | +} | |
| 160 | + | |
| 161 | +long | |
| 162 | +mousewrite(Chan *c, void *va, long n, vlong offset) | |
| 163 | +{ | |
| 164 | + char *p; | |
| 165 | + Point pt; | |
| 166 | + char buf[64]; | |
| 167 | + | |
| 168 | + USED(offset); | |
| 169 | + | |
| 170 | + p = va; | |
| 171 | + switch((long)c->qid.path){ | |
| 172 | + case Qdir: | |
| 173 | + error(Eisdir); | |
| 174 | + | |
| 175 | + case Qcursor: | |
| 176 | + if(n < 2*4+2*2*16){ | |
| 177 | + cursorarrow(); | |
| 178 | + }else{ | |
| 179 | + n = 2*4+2*2*16; | |
| 180 | + lock(&cursor.lk); | |
| 181 | + cursor.offset.x = BGLONG(p+0); | |
| 182 | + cursor.offset.y = BGLONG(p+4); | |
| 183 | + memmove(cursor.clr, p+8, 2*16); | |
| 184 | + memmove(cursor.set, p+40, 2*16); | |
| 185 | + unlock(&cursor.lk); | |
| 186 | + setcursor(); | |
| 187 | + } | |
| 188 | + return n; | |
| 189 | + | |
| 190 | + case Qmouse: | |
| 191 | + if(n > sizeof buf-1) | |
| 192 | + n = sizeof buf -1; | |
| 193 | + memmove(buf, va, n); | |
| 194 | + buf[n] = 0; | |
| 195 | + p = 0; | |
| 196 | + pt.x = strtoul(buf+1, &p, 0); | |
| 197 | + if(p == 0) | |
| 198 | + error(Eshort); | |
| 199 | + pt.y = strtoul(p, 0, 0); | |
| 200 | + if(ptinrect(pt, gscreen->r)) | |
| 201 | + mouseset(pt); | |
| 202 | + return n; | |
| 203 | + } | |
| 204 | + | |
| 205 | + error(Egreg); | |
| 206 | + return -1; | |
| 207 | +} | |
| 208 | + | |
| 209 | +int | |
| 210 | +mousechanged(void *a) | |
| 211 | +{ | |
| 212 | + USED(a); | |
| 213 | + | |
| 214 | + return mouse.ri != mouse.wi || screen.reshaped; | |
| 215 | +} | |
| 216 | + | |
| 217 | +Dev mousedevtab = { | |
| 218 | + 'm', | |
| 219 | + "mouse", | |
| 220 | + | |
| 221 | + devreset, | |
| 222 | + devinit, | |
| 223 | + devshutdown, | |
| 224 | + mouseattach, | |
| 225 | + mousewalk, | |
| 226 | + mousestat, | |
| 227 | + mouseopen, | |
| 228 | + devcreate, | |
| 229 | + mouseclose, | |
| 230 | + mouseread, | |
| 231 | + devbread, | |
| 232 | + mousewrite, | |
| 233 | + devbwrite, | |
| 234 | + devremove, | |
| 235 | + devwstat, | |
| 236 | +}; | |
| 237 | + | |
| @@ -0,0 +1,704 @@ | ||
| 1 | +#include <windows.h> | |
| 2 | +#include <sys/types.h> | |
| 3 | +#include <sys/stat.h> | |
| 4 | +#include <fcntl.h> | |
| 5 | + | |
| 6 | +#ifndef NAME_MAX | |
| 7 | +# define NAME_MAX 256 | |
| 8 | +#endif | |
| 9 | +#include "u.h" | |
| 10 | +#include "lib.h" | |
| 11 | +#include "dat.h" | |
| 12 | +#include "fns.h" | |
| 13 | +#include "error.h" | |
| 14 | + | |
| 15 | +typedef struct DIR DIR; | |
| 16 | +typedef struct Ufsinfo Ufsinfo; | |
| 17 | + | |
| 18 | +enum | |
| 19 | +{ | |
| 20 | + NUID = 256, | |
| 21 | + NGID = 256, | |
| 22 | + MAXPATH = 1024, | |
| 23 | + MAXCOMP = 128 | |
| 24 | +}; | |
| 25 | + | |
| 26 | +struct DIR | |
| 27 | +{ | |
| 28 | + HANDLE handle; | |
| 29 | + char* path; | |
| 30 | + int index; | |
| 31 | + WIN32_FIND_DATA wfd; | |
| 32 | +}; | |
| 33 | + | |
| 34 | +struct Ufsinfo | |
| 35 | +{ | |
| 36 | + int mode; | |
| 37 | + int fd; | |
| 38 | + int uid; | |
| 39 | + int gid; | |
| 40 | + DIR* dir; | |
| 41 | + ulong offset; | |
| 42 | + QLock oq; | |
| 43 | + char nextname[NAME_MAX]; | |
| 44 | +}; | |
| 45 | + | |
| 46 | +DIR* opendir(char*); | |
| 47 | +int readdir(char*, DIR*); | |
| 48 | +void closedir(DIR*); | |
| 49 | +void rewinddir(DIR*); | |
| 50 | + | |
| 51 | +char *base = "c:/."; | |
| 52 | + | |
| 53 | +static Qid fsqid(char*, struct stat *); | |
| 54 | +static void fspath(Chan*, char*, char*); | |
| 55 | +// static void fsperm(Chan*, int); | |
| 56 | +static ulong fsdirread(Chan*, uchar*, int, ulong); | |
| 57 | +static int fsomode(int); | |
| 58 | +static int chown(char *path, int uid, int); | |
| 59 | +static int link(char *path, char *next); | |
| 60 | + | |
| 61 | +/* clumsy hack, but not worse than the Path stuff in the last one */ | |
| 62 | +static char* | |
| 63 | +uc2name(Chan *c) | |
| 64 | +{ | |
| 65 | + char *s; | |
| 66 | + | |
| 67 | + if(c->name == nil) | |
| 68 | + return "/"; | |
| 69 | + s = c2name(c); | |
| 70 | + if(s[0]=='#' && s[1]=='U') | |
| 71 | + return s+2; | |
| 72 | + return s; | |
| 73 | +} | |
| 74 | + | |
| 75 | +static char* | |
| 76 | +lastelem(Chan *c) | |
| 77 | +{ | |
| 78 | + char *s, *t; | |
| 79 | + | |
| 80 | + s = uc2name(c); | |
| 81 | + if((t = strrchr(s, '/')) == nil) | |
| 82 | + return s; | |
| 83 | + if(t[1] == 0) | |
| 84 | + return t; | |
| 85 | + return t+1; | |
| 86 | +} | |
| 87 | + | |
| 88 | +static Chan* | |
| 89 | +fsattach(void *spec) | |
| 90 | +{ | |
| 91 | + Chan *c; | |
| 92 | + struct stat stbuf; | |
| 93 | + static int devno; | |
| 94 | + Ufsinfo *uif; | |
| 95 | + | |
| 96 | + if(stat(base, &stbuf) < 0) | |
| 97 | + error(strerror(errno)); | |
| 98 | + | |
| 99 | + c = devattach('U', spec); | |
| 100 | + | |
| 101 | + uif = mallocz(sizeof(Ufsinfo), 1); | |
| 102 | + uif->gid = stbuf.st_gid; | |
| 103 | + uif->uid = stbuf.st_uid; | |
| 104 | + uif->mode = stbuf.st_mode; | |
| 105 | + | |
| 106 | + c->aux = uif; | |
| 107 | + c->dev = devno++; | |
| 108 | + c->qid.type = QTDIR; | |
| 109 | +/*print("fsattach %s\n", c2name(c));*/ | |
| 110 | + | |
| 111 | + return c; | |
| 112 | +} | |
| 113 | + | |
| 114 | +static Chan* | |
| 115 | +fsclone(Chan *c, Chan *nc) | |
| 116 | +{ | |
| 117 | + Ufsinfo *uif; | |
| 118 | + | |
| 119 | + uif = mallocz(sizeof(Ufsinfo), 1); | |
| 120 | + *uif = *(Ufsinfo*)c->aux; | |
| 121 | + nc->aux = uif; | |
| 122 | + | |
| 123 | + return nc; | |
| 124 | +} | |
| 125 | + | |
| 126 | +static int | |
| 127 | +fswalk1(Chan *c, char *name) | |
| 128 | +{ | |
| 129 | + struct stat stbuf; | |
| 130 | + char path[MAXPATH]; | |
| 131 | + Ufsinfo *uif; | |
| 132 | + | |
| 133 | + fspath(c, name, path); | |
| 134 | + | |
| 135 | + /* print("** fs walk '%s' -> %s\n", path, name); /**/ | |
| 136 | + | |
| 137 | + if(stat(path, &stbuf) < 0) | |
| 138 | + return 0; | |
| 139 | + | |
| 140 | + uif = c->aux; | |
| 141 | + | |
| 142 | + uif->gid = stbuf.st_gid; | |
| 143 | + uif->uid = stbuf.st_uid; | |
| 144 | + uif->mode = stbuf.st_mode; | |
| 145 | + | |
| 146 | + c->qid = fsqid(path, &stbuf); | |
| 147 | + | |
| 148 | + return 1; | |
| 149 | +} | |
| 150 | + | |
| 151 | +extern Cname* addelem(Cname*, char*); | |
| 152 | + | |
| 153 | +static Walkqid* | |
| 154 | +fswalk(Chan *c, Chan *nc, char **name, int nname) | |
| 155 | +{ | |
| 156 | + int i; | |
| 157 | + Cname *cname; | |
| 158 | + Walkqid *wq; | |
| 159 | + | |
| 160 | + if(nc != nil) | |
| 161 | + panic("fswalk: nc != nil"); | |
| 162 | + wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); | |
| 163 | + nc = devclone(c); | |
| 164 | + cname = c->name; | |
| 165 | + incref(&cname->ref); | |
| 166 | + | |
| 167 | + fsclone(c, nc); | |
| 168 | + wq->clone = nc; | |
| 169 | + for(i=0; i<nname; i++){ | |
| 170 | + nc->name = cname; | |
| 171 | + if(fswalk1(nc, name[i]) == 0) | |
| 172 | + break; | |
| 173 | + cname = addelem(cname, name[i]); | |
| 174 | + wq->qid[i] = nc->qid; | |
| 175 | + } | |
| 176 | + nc->name = nil; | |
| 177 | + cnameclose(cname); | |
| 178 | + if(i != nname){ | |
| 179 | + cclose(nc); | |
| 180 | + wq->clone = nil; | |
| 181 | + } | |
| 182 | + wq->nqid = i; | |
| 183 | + return wq; | |
| 184 | +} | |
| 185 | + | |
| 186 | +static int | |
| 187 | +fsstat(Chan *c, uchar *buf, int n) | |
| 188 | +{ | |
| 189 | + Dir d; | |
| 190 | + struct stat stbuf; | |
| 191 | + char path[MAXPATH]; | |
| 192 | + | |
| 193 | + if(n < BIT16SZ) | |
| 194 | + error(Eshortstat); | |
| 195 | + | |
| 196 | + fspath(c, 0, path); | |
| 197 | + if(stat(path, &stbuf) < 0) | |
| 198 | + error(strerror(errno)); | |
| 199 | + | |
| 200 | + d.name = lastelem(c); | |
| 201 | + d.uid = "unknown"; | |
| 202 | + d.gid = "unknown"; | |
| 203 | + d.muid = "unknown"; | |
| 204 | + d.qid = c->qid; | |
| 205 | + d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777); | |
| 206 | + d.atime = stbuf.st_atime; | |
| 207 | + d.mtime = stbuf.st_mtime; | |
| 208 | + d.length = stbuf.st_size; | |
| 209 | + d.type = 'U'; | |
| 210 | + d.dev = c->dev; | |
| 211 | + return convD2M(&d, buf, n); | |
| 212 | +} | |
| 213 | + | |
| 214 | +static Chan* | |
| 215 | +fsopen(Chan *c, int mode) | |
| 216 | +{ | |
| 217 | + char path[MAXPATH]; | |
| 218 | + int m, isdir; | |
| 219 | + Ufsinfo *uif; | |
| 220 | + | |
| 221 | +/*print("fsopen %s\n", c2name(c));*/ | |
| 222 | + m = mode & (OTRUNC|3); | |
| 223 | + switch(m) { | |
| 224 | + case 0: | |
| 225 | + break; | |
| 226 | + case 1: | |
| 227 | + case 1|16: | |
| 228 | + break; | |
| 229 | + case 2: | |
| 230 | + case 0|16: | |
| 231 | + case 2|16: | |
| 232 | + break; | |
| 233 | + case 3: | |
| 234 | + break; | |
| 235 | + default: | |
| 236 | + error(Ebadarg); | |
| 237 | + } | |
| 238 | + | |
| 239 | + isdir = c->qid.type & QTDIR; | |
| 240 | + | |
| 241 | + if(isdir && mode != OREAD) | |
| 242 | + error(Eperm); | |
| 243 | + | |
| 244 | + m = fsomode(m & 3); | |
| 245 | + c->mode = openmode(mode); | |
| 246 | + | |
| 247 | + uif = c->aux; | |
| 248 | + | |
| 249 | + fspath(c, 0, path); | |
| 250 | + if(isdir) { | |
| 251 | + uif->dir = opendir(path); | |
| 252 | + if(uif->dir == 0) | |
| 253 | + error(strerror(errno)); | |
| 254 | + } | |
| 255 | + else { | |
| 256 | + if(mode & OTRUNC) | |
| 257 | + m |= O_TRUNC; | |
| 258 | + uif->fd = open(path, m|_O_BINARY, 0666); | |
| 259 | + | |
| 260 | + if(uif->fd < 0) | |
| 261 | + error(strerror(errno)); | |
| 262 | + } | |
| 263 | + uif->offset = 0; | |
| 264 | + | |
| 265 | + c->offset = 0; | |
| 266 | + c->flag |= COPEN; | |
| 267 | + return c; | |
| 268 | +} | |
| 269 | + | |
| 270 | +static void | |
| 271 | +fscreate(Chan *c, char *name, int mode, ulong perm) | |
| 272 | +{ | |
| 273 | + int fd, m; | |
| 274 | + char path[MAXPATH]; | |
| 275 | + struct stat stbuf; | |
| 276 | + Ufsinfo *uif; | |
| 277 | + | |
| 278 | + m = fsomode(mode&3); | |
| 279 | + | |
| 280 | + fspath(c, name, path); | |
| 281 | + | |
| 282 | + uif = c->aux; | |
| 283 | + | |
| 284 | + if(perm & DMDIR) { | |
| 285 | + if(m) | |
| 286 | + error(Eperm); | |
| 287 | + | |
| 288 | + if(mkdir(path) < 0) | |
| 289 | + error(strerror(errno)); | |
| 290 | + | |
| 291 | + fd = open(path, 0); | |
| 292 | + if(fd >= 0) { | |
| 293 | + chmod(path, perm & 0777); | |
| 294 | + chown(path, uif->uid, uif->uid); | |
| 295 | + } | |
| 296 | + close(fd); | |
| 297 | + | |
| 298 | + uif->dir = opendir(path); | |
| 299 | + if(uif->dir == 0) | |
| 300 | + error(strerror(errno)); | |
| 301 | + } | |
| 302 | + else { | |
| 303 | + fd = open(path, _O_WRONLY|_O_BINARY|_O_CREAT|_O_TRUNC, 0666); | |
| 304 | + if(fd >= 0) { | |
| 305 | + if(m != 1) { | |
| 306 | + close(fd); | |
| 307 | + fd = open(path, m|_O_BINARY); | |
| 308 | + } | |
| 309 | + chmod(path, perm & 0777); | |
| 310 | + chown(path, uif->uid, uif->gid); | |
| 311 | + } | |
| 312 | + if(fd < 0) | |
| 313 | + error(strerror(errno)); | |
| 314 | + uif->fd = fd; | |
| 315 | + } | |
| 316 | + | |
| 317 | + if(stat(path, &stbuf) < 0) | |
| 318 | + error(strerror(errno)); | |
| 319 | + c->qid = fsqid(path, &stbuf); | |
| 320 | + c->offset = 0; | |
| 321 | + c->flag |= COPEN; | |
| 322 | + c->mode = openmode(mode); | |
| 323 | +} | |
| 324 | + | |
| 325 | +static void | |
| 326 | +fsclose(Chan *c) | |
| 327 | +{ | |
| 328 | + Ufsinfo *uif; | |
| 329 | + | |
| 330 | + uif = c->aux; | |
| 331 | + | |
| 332 | + if(c->flag & COPEN) { | |
| 333 | + if(c->qid.type & QTDIR) | |
| 334 | + closedir(uif->dir); | |
| 335 | + else | |
| 336 | + close(uif->fd); | |
| 337 | + } | |
| 338 | + | |
| 339 | + free(uif); | |
| 340 | +} | |
| 341 | + | |
| 342 | +static long | |
| 343 | +fsread(Chan *c, void *va, long n, ulong offset) | |
| 344 | +{ | |
| 345 | + int fd, r; | |
| 346 | + Ufsinfo *uif; | |
| 347 | + | |
| 348 | +/*print("fsread %s\n", c2name(c));*/ | |
| 349 | + if(c->qid.type & QTDIR) | |
| 350 | + return fsdirread(c, va, n, offset); | |
| 351 | + | |
| 352 | + uif = c->aux; | |
| 353 | + qlock(&uif->oq); | |
| 354 | + if(waserror()) { | |
| 355 | + qunlock(&uif->oq); | |
| 356 | + nexterror(); | |
| 357 | + } | |
| 358 | + fd = uif->fd; | |
| 359 | + if(uif->offset != offset) { | |
| 360 | + r = lseek(fd, offset, 0); | |
| 361 | + if(r < 0) | |
| 362 | + error(strerror(errno)); | |
| 363 | + uif->offset = offset; | |
| 364 | + } | |
| 365 | + | |
| 366 | + n = read(fd, va, n); | |
| 367 | + if(n < 0) | |
| 368 | + error(strerror(errno)); | |
| 369 | + | |
| 370 | + uif->offset += n; | |
| 371 | + qunlock(&uif->oq); | |
| 372 | + poperror(); | |
| 373 | + | |
| 374 | + return n; | |
| 375 | +} | |
| 376 | + | |
| 377 | +static long | |
| 378 | +fswrite(Chan *c, void *va, long n, ulong offset) | |
| 379 | +{ | |
| 380 | + int fd, r; | |
| 381 | + Ufsinfo *uif; | |
| 382 | + | |
| 383 | + uif = c->aux; | |
| 384 | + | |
| 385 | + qlock(&uif->oq); | |
| 386 | + if(waserror()) { | |
| 387 | + qunlock(&uif->oq); | |
| 388 | + nexterror(); | |
| 389 | + } | |
| 390 | + fd = uif->fd; | |
| 391 | + if(uif->offset != offset) { | |
| 392 | + r = lseek(fd, offset, 0); | |
| 393 | + if(r < 0) | |
| 394 | + error(strerror(errno)); | |
| 395 | + uif->offset = offset; | |
| 396 | + } | |
| 397 | + | |
| 398 | + n = write(fd, va, n); | |
| 399 | + if(n < 0) | |
| 400 | + error(strerror(errno)); | |
| 401 | + | |
| 402 | + uif->offset += n; | |
| 403 | + qunlock(&uif->oq); | |
| 404 | + poperror(); | |
| 405 | + | |
| 406 | + return n; | |
| 407 | +} | |
| 408 | + | |
| 409 | +static void | |
| 410 | +fsremove(Chan *c) | |
| 411 | +{ | |
| 412 | + int n; | |
| 413 | + char path[MAXPATH]; | |
| 414 | + | |
| 415 | + fspath(c, 0, path); | |
| 416 | + if(c->qid.type & QTDIR) | |
| 417 | + n = rmdir(path); | |
| 418 | + else | |
| 419 | + n = remove(path); | |
| 420 | + if(n < 0) | |
| 421 | + error(strerror(errno)); | |
| 422 | +} | |
| 423 | + | |
| 424 | +static int | |
| 425 | +fswstat(Chan *c, uchar *buf, int n) | |
| 426 | +{ | |
| 427 | + Dir d; | |
| 428 | + struct stat stbuf; | |
| 429 | + char old[MAXPATH], new[MAXPATH]; | |
| 430 | + char strs[MAXPATH*3], *p; | |
| 431 | + Ufsinfo *uif; | |
| 432 | + | |
| 433 | + if (convM2D(buf, n, &d, strs) != n) | |
| 434 | + error(Ebadstat); | |
| 435 | + | |
| 436 | + fspath(c, 0, old); | |
| 437 | + if(stat(old, &stbuf) < 0) | |
| 438 | + error(strerror(errno)); | |
| 439 | + | |
| 440 | + uif = c->aux; | |
| 441 | + | |
| 442 | +// if(uif->uid != stbuf.st_uid) | |
| 443 | +// error(Eowner); | |
| 444 | + | |
| 445 | + if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) { | |
| 446 | + fspath(c, 0, old); | |
| 447 | + strcpy(new, old); | |
| 448 | + p = strrchr(new, '/'); | |
| 449 | + strcpy(p+1, d.name); | |
| 450 | + if(rename(old, new) < 0) | |
| 451 | + error(strerror(errno)); | |
| 452 | + } | |
| 453 | + | |
| 454 | + fspath(c, 0, old); | |
| 455 | + if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) { | |
| 456 | + if(chmod(old, d.mode&0777) < 0) | |
| 457 | + error(strerror(errno)); | |
| 458 | + uif->mode &= ~0777; | |
| 459 | + uif->mode |= d.mode&0777; | |
| 460 | + } | |
| 461 | +/* | |
| 462 | + p = name2pass(gid, d.gid); | |
| 463 | + if(p == 0) | |
| 464 | + error(Eunknown); | |
| 465 | + | |
| 466 | + if(p->id != stbuf.st_gid) { | |
| 467 | + if(chown(old, stbuf.st_uid, p->id) < 0) | |
| 468 | + error(sys_errlist[errno]); | |
| 469 | + | |
| 470 | + uif->gid = p->id; | |
| 471 | + } | |
| 472 | +*/ | |
| 473 | + return n; | |
| 474 | +} | |
| 475 | + | |
| 476 | +static Qid | |
| 477 | +fsqid(char *p, struct stat *st) | |
| 478 | +{ | |
| 479 | + Qid q; | |
| 480 | + int dev; | |
| 481 | + ulong h; | |
| 482 | + static int nqdev; | |
| 483 | + static uchar *qdev; | |
| 484 | + | |
| 485 | + if(qdev == 0) | |
| 486 | + qdev = mallocz(65536U, 1); | |
| 487 | + | |
| 488 | + q.type = 0; | |
| 489 | + if((st->st_mode&S_IFMT) == S_IFDIR) | |
| 490 | + q.type = QTDIR; | |
| 491 | + | |
| 492 | + dev = st->st_dev & 0xFFFFUL; | |
| 493 | + if(qdev[dev] == 0) | |
| 494 | + qdev[dev] = ++nqdev; | |
| 495 | + | |
| 496 | + h = 0; | |
| 497 | + while(*p != '\0') | |
| 498 | + h += *p++ * 13; | |
| 499 | + | |
| 500 | + q.path = (vlong)qdev[dev]<<32; | |
| 501 | + q.path |= h; | |
| 502 | + q.vers = st->st_mtime; | |
| 503 | + | |
| 504 | + return q; | |
| 505 | +} | |
| 506 | + | |
| 507 | +static void | |
| 508 | +fspath(Chan *c, char *ext, char *path) | |
| 509 | +{ | |
| 510 | + strcpy(path, base); | |
| 511 | + strcat(path, "/"); | |
| 512 | + strcat(path, uc2name(c)); | |
| 513 | + if(ext) { | |
| 514 | + strcat(path, "/"); | |
| 515 | + strcat(path, ext); | |
| 516 | + } | |
| 517 | + cleanname(path); | |
| 518 | +} | |
| 519 | + | |
| 520 | +static int | |
| 521 | +isdots(char *name) | |
| 522 | +{ | |
| 523 | + if(name[0] != '.') | |
| 524 | + return 0; | |
| 525 | + if(name[1] == '\0') | |
| 526 | + return 1; | |
| 527 | + if(name[1] != '.') | |
| 528 | + return 0; | |
| 529 | + if(name[2] == '\0') | |
| 530 | + return 1; | |
| 531 | + return 0; | |
| 532 | +} | |
| 533 | + | |
| 534 | +static int | |
| 535 | +p9readdir(char *name, Ufsinfo *uif) | |
| 536 | +{ | |
| 537 | + if(uif->nextname[0]){ | |
| 538 | + strcpy(name, uif->nextname); | |
| 539 | + uif->nextname[0] = 0; | |
| 540 | + return 1; | |
| 541 | + } | |
| 542 | + | |
| 543 | + return readdir(name, uif->dir); | |
| 544 | +} | |
| 545 | + | |
| 546 | +static ulong | |
| 547 | +fsdirread(Chan *c, uchar *va, int count, ulong offset) | |
| 548 | +{ | |
| 549 | + int i; | |
| 550 | + Dir d; | |
| 551 | + long n; | |
| 552 | + char de[NAME_MAX]; | |
| 553 | + struct stat stbuf; | |
| 554 | + char path[MAXPATH], dirpath[MAXPATH]; | |
| 555 | + Ufsinfo *uif; | |
| 556 | + | |
| 557 | +/*print("fsdirread %s\n", c2name(c));*/ | |
| 558 | + i = 0; | |
| 559 | + uif = c->aux; | |
| 560 | + | |
| 561 | + errno = 0; | |
| 562 | + if(uif->offset != offset) { | |
| 563 | + if(offset != 0) | |
| 564 | + error("bad offset in fsdirread"); | |
| 565 | + uif->offset = offset; /* sync offset */ | |
| 566 | + uif->nextname[0] = 0; | |
| 567 | + rewinddir(uif->dir); | |
| 568 | + } | |
| 569 | + | |
| 570 | + fspath(c, 0, dirpath); | |
| 571 | + | |
| 572 | + while(i+BIT16SZ < count) { | |
| 573 | + if(!p9readdir(de, uif)) | |
| 574 | + break; | |
| 575 | + | |
| 576 | + if(de[0]==0 || isdots(de)) | |
| 577 | + continue; | |
| 578 | + | |
| 579 | + d.name = de; | |
| 580 | + sprint(path, "%s/%s", dirpath, de); | |
| 581 | + memset(&stbuf, 0, sizeof stbuf); | |
| 582 | + | |
| 583 | + if(stat(path, &stbuf) < 0) { | |
| 584 | + print("dir: bad path %s\n", path); | |
| 585 | + /* but continue... probably a bad symlink */ | |
| 586 | + } | |
| 587 | + | |
| 588 | + d.uid = "unknown"; | |
| 589 | + d.gid = "unknown"; | |
| 590 | + d.muid = "unknown"; | |
| 591 | + d.qid = fsqid(path, &stbuf); | |
| 592 | + d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777); | |
| 593 | + d.atime = stbuf.st_atime; | |
| 594 | + d.mtime = stbuf.st_mtime; | |
| 595 | + d.length = stbuf.st_size; | |
| 596 | + d.type = 'U'; | |
| 597 | + d.dev = c->dev; | |
| 598 | + n = convD2M(&d, (char*)va+i, count-i); | |
| 599 | + if(n == BIT16SZ){ | |
| 600 | + strcpy(uif->nextname, de); | |
| 601 | + break; | |
| 602 | + } | |
| 603 | + i += n; | |
| 604 | + } | |
| 605 | +/*print("got %d\n", i);*/ | |
| 606 | + uif->offset += i; | |
| 607 | + return i; | |
| 608 | +} | |
| 609 | + | |
| 610 | +static int | |
| 611 | +fsomode(int m) | |
| 612 | +{ | |
| 613 | + switch(m) { | |
| 614 | + case 0: /* OREAD */ | |
| 615 | + case 3: /* OEXEC */ | |
| 616 | + return 0; | |
| 617 | + case 1: /* OWRITE */ | |
| 618 | + return 1; | |
| 619 | + case 2: /* ORDWR */ | |
| 620 | + return 2; | |
| 621 | + } | |
| 622 | + error(Ebadarg); | |
| 623 | + return 0; | |
| 624 | +} | |
| 625 | +void | |
| 626 | +closedir(DIR *d) | |
| 627 | +{ | |
| 628 | + FindClose(d->handle); | |
| 629 | + free(d->path); | |
| 630 | +} | |
| 631 | + | |
| 632 | +int | |
| 633 | +readdir(char *name, DIR *d) | |
| 634 | +{ | |
| 635 | + if(d->index != 0) { | |
| 636 | + if(FindNextFile(d->handle, &d->wfd) == FALSE) | |
| 637 | + return 0; | |
| 638 | + } | |
| 639 | + strcpy(name, d->wfd.cFileName); | |
| 640 | + d->index++; | |
| 641 | + | |
| 642 | + return 1; | |
| 643 | +} | |
| 644 | + | |
| 645 | +void | |
| 646 | +rewinddir(DIR *d) | |
| 647 | +{ | |
| 648 | + FindClose(d->handle); | |
| 649 | + d->handle = FindFirstFile(d->path, &d->wfd); | |
| 650 | + d->index = 0; | |
| 651 | +} | |
| 652 | + | |
| 653 | +static int | |
| 654 | +chown(char *path, int uid, int perm) | |
| 655 | +{ | |
| 656 | +/* panic("chown"); */ | |
| 657 | + return 0; | |
| 658 | +} | |
| 659 | + | |
| 660 | +DIR* | |
| 661 | +opendir(char *p) | |
| 662 | +{ | |
| 663 | + DIR *d; | |
| 664 | + char path[MAX_PATH]; | |
| 665 | + | |
| 666 | + | |
| 667 | + snprint(path, sizeof(path), "%s/*.*", p); | |
| 668 | + | |
| 669 | + d = mallocz(sizeof(DIR), 1); | |
| 670 | + if(d == 0) | |
| 671 | + return 0; | |
| 672 | + | |
| 673 | + d->index = 0; | |
| 674 | + | |
| 675 | + d->handle = FindFirstFile(path, &d->wfd); | |
| 676 | + if(d->handle == INVALID_HANDLE_VALUE) { | |
| 677 | + free(d); | |
| 678 | + return 0; | |
| 679 | + } | |
| 680 | + | |
| 681 | + d->path = strdup(path); | |
| 682 | + return d; | |
| 683 | +} | |
| 684 | + | |
| 685 | +Dev fsdevtab = { | |
| 686 | + 'U', | |
| 687 | + "fs", | |
| 688 | + | |
| 689 | + devreset, | |
| 690 | + devinit, | |
| 691 | + devshutdown, | |
| 692 | + fsattach, | |
| 693 | + fswalk, | |
| 694 | + fsstat, | |
| 695 | + fsopen, | |
| 696 | + fscreate, | |
| 697 | + fsclose, | |
| 698 | + fsread, | |
| 699 | + devbread, | |
| 700 | + fswrite, | |
| 701 | + devbwrite, | |
| 702 | + fsremove, | |
| 703 | + fswstat, | |
| 704 | +}; | |
| @@ -0,0 +1,398 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +#include "netif.h" | |
| 8 | + | |
| 9 | +typedef struct Pipe Pipe; | |
| 10 | +struct Pipe | |
| 11 | +{ | |
| 12 | + QLock lk; | |
| 13 | + Pipe *next; | |
| 14 | + int ref; | |
| 15 | + ulong path; | |
| 16 | + Queue *q[2]; | |
| 17 | + int qref[2]; | |
| 18 | +}; | |
| 19 | + | |
| 20 | +struct | |
| 21 | +{ | |
| 22 | + Lock lk; | |
| 23 | + ulong path; | |
| 24 | +} pipealloc; | |
| 25 | + | |
| 26 | +enum | |
| 27 | +{ | |
| 28 | + Qdir, | |
| 29 | + Qdata0, | |
| 30 | + Qdata1, | |
| 31 | +}; | |
| 32 | + | |
| 33 | +Dirtab pipedir[] = | |
| 34 | +{ | |
| 35 | + ".", {Qdir,0,QTDIR}, 0, DMDIR|0500, | |
| 36 | + "data", {Qdata0}, 0, 0600, | |
| 37 | + "data1", {Qdata1}, 0, 0600, | |
| 38 | +}; | |
| 39 | +#define NPIPEDIR 3 | |
| 40 | + | |
| 41 | +static void | |
| 42 | +pipeinit(void) | |
| 43 | +{ | |
| 44 | + if(conf.pipeqsize == 0){ | |
| 45 | + if(conf.nmach > 1) | |
| 46 | + conf.pipeqsize = 256*1024; | |
| 47 | + else | |
| 48 | + conf.pipeqsize = 32*1024; | |
| 49 | + } | |
| 50 | +} | |
| 51 | + | |
| 52 | +/* | |
| 53 | + * create a pipe, no streams are created until an open | |
| 54 | + */ | |
| 55 | +static Chan* | |
| 56 | +pipeattach(char *spec) | |
| 57 | +{ | |
| 58 | + Pipe *p; | |
| 59 | + Chan *c; | |
| 60 | + | |
| 61 | + c = devattach('|', spec); | |
| 62 | + p = malloc(sizeof(Pipe)); | |
| 63 | + if(p == 0) | |
| 64 | + exhausted("memory"); | |
| 65 | + p->ref = 1; | |
| 66 | + | |
| 67 | + p->q[0] = qopen(conf.pipeqsize, 0, 0, 0); | |
| 68 | + if(p->q[0] == 0){ | |
| 69 | + free(p); | |
| 70 | + exhausted("memory"); | |
| 71 | + } | |
| 72 | + p->q[1] = qopen(conf.pipeqsize, 0, 0, 0); | |
| 73 | + if(p->q[1] == 0){ | |
| 74 | + free(p->q[0]); | |
| 75 | + free(p); | |
| 76 | + exhausted("memory"); | |
| 77 | + } | |
| 78 | + | |
| 79 | + lock(&pipealloc.lk); | |
| 80 | + p->path = ++pipealloc.path; | |
| 81 | + unlock(&pipealloc.lk); | |
| 82 | + | |
| 83 | + mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR); | |
| 84 | + c->aux = p; | |
| 85 | + c->dev = 0; | |
| 86 | + return c; | |
| 87 | +} | |
| 88 | + | |
| 89 | +static int | |
| 90 | +pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) | |
| 91 | +{ | |
| 92 | + Qid q; | |
| 93 | + int len; | |
| 94 | + Pipe *p; | |
| 95 | + | |
| 96 | + USED(name); | |
| 97 | + | |
| 98 | + if(i == DEVDOTDOT){ | |
| 99 | + devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp); | |
| 100 | + return 1; | |
| 101 | + } | |
| 102 | + i++; /* skip . */ | |
| 103 | + if(tab==0 || i>=ntab) | |
| 104 | + return -1; | |
| 105 | + | |
| 106 | + tab += i; | |
| 107 | + p = c->aux; | |
| 108 | + switch((ulong)tab->qid.path){ | |
| 109 | + case Qdata0: | |
| 110 | + len = qlen(p->q[0]); | |
| 111 | + break; | |
| 112 | + case Qdata1: | |
| 113 | + len = qlen(p->q[1]); | |
| 114 | + break; | |
| 115 | + default: | |
| 116 | + len = tab->length; | |
| 117 | + break; | |
| 118 | + } | |
| 119 | + mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE); | |
| 120 | + devdir(c, q, tab->name, len, eve, tab->perm, dp); | |
| 121 | + return 1; | |
| 122 | +} | |
| 123 | + | |
| 124 | + | |
| 125 | +static Walkqid* | |
| 126 | +pipewalk(Chan *c, Chan *nc, char **name, int nname) | |
| 127 | +{ | |
| 128 | + Walkqid *wq; | |
| 129 | + Pipe *p; | |
| 130 | + | |
| 131 | + wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen); | |
| 132 | + if(wq != nil && wq->clone != nil && wq->clone != c){ | |
| 133 | + p = c->aux; | |
| 134 | + qlock(&p->lk); | |
| 135 | + p->ref++; | |
| 136 | + if(c->flag & COPEN){ | |
| 137 | + print("channel open in pipewalk\n"); | |
| 138 | + switch(NETTYPE(c->qid.path)){ | |
| 139 | + case Qdata0: | |
| 140 | + p->qref[0]++; | |
| 141 | + break; | |
| 142 | + case Qdata1: | |
| 143 | + p->qref[1]++; | |
| 144 | + break; | |
| 145 | + } | |
| 146 | + } | |
| 147 | + qunlock(&p->lk); | |
| 148 | + } | |
| 149 | + return wq; | |
| 150 | +} | |
| 151 | + | |
| 152 | +static int | |
| 153 | +pipestat(Chan *c, uchar *db, int n) | |
| 154 | +{ | |
| 155 | + Pipe *p; | |
| 156 | + Dir dir; | |
| 157 | + | |
| 158 | + p = c->aux; | |
| 159 | + | |
| 160 | + switch(NETTYPE(c->qid.path)){ | |
| 161 | + case Qdir: | |
| 162 | + devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir); | |
| 163 | + break; | |
| 164 | + case Qdata0: | |
| 165 | + devdir(c, c->qid, "data", qlen(p->q[0]), eve, 0600, &dir); | |
| 166 | + break; | |
| 167 | + case Qdata1: | |
| 168 | + devdir(c, c->qid, "data1", qlen(p->q[1]), eve, 0600, &dir); | |
| 169 | + break; | |
| 170 | + default: | |
| 171 | + panic("pipestat"); | |
| 172 | + } | |
| 173 | + n = convD2M(&dir, db, n); | |
| 174 | + if(n < BIT16SZ) | |
| 175 | + error(Eshortstat); | |
| 176 | + return n; | |
| 177 | +} | |
| 178 | + | |
| 179 | +/* | |
| 180 | + * if the stream doesn't exist, create it | |
| 181 | + */ | |
| 182 | +static Chan* | |
| 183 | +pipeopen(Chan *c, int omode) | |
| 184 | +{ | |
| 185 | + Pipe *p; | |
| 186 | + | |
| 187 | + if(c->qid.type & QTDIR){ | |
| 188 | + if(omode != OREAD) | |
| 189 | + error(Ebadarg); | |
| 190 | + c->mode = omode; | |
| 191 | + c->flag |= COPEN; | |
| 192 | + c->offset = 0; | |
| 193 | + return c; | |
| 194 | + } | |
| 195 | + | |
| 196 | + p = c->aux; | |
| 197 | + qlock(&p->lk); | |
| 198 | + switch(NETTYPE(c->qid.path)){ | |
| 199 | + case Qdata0: | |
| 200 | + p->qref[0]++; | |
| 201 | + break; | |
| 202 | + case Qdata1: | |
| 203 | + p->qref[1]++; | |
| 204 | + break; | |
| 205 | + } | |
| 206 | + qunlock(&p->lk); | |
| 207 | + | |
| 208 | + c->mode = openmode(omode); | |
| 209 | + c->flag |= COPEN; | |
| 210 | + c->offset = 0; | |
| 211 | + c->iounit = qiomaxatomic; | |
| 212 | + return c; | |
| 213 | +} | |
| 214 | + | |
| 215 | +static void | |
| 216 | +pipeclose(Chan *c) | |
| 217 | +{ | |
| 218 | + Pipe *p; | |
| 219 | + | |
| 220 | + p = c->aux; | |
| 221 | + qlock(&p->lk); | |
| 222 | + | |
| 223 | + if(c->flag & COPEN){ | |
| 224 | + /* | |
| 225 | + * closing either side hangs up the stream | |
| 226 | + */ | |
| 227 | + switch(NETTYPE(c->qid.path)){ | |
| 228 | + case Qdata0: | |
| 229 | + p->qref[0]--; | |
| 230 | + if(p->qref[0] == 0){ | |
| 231 | + qhangup(p->q[1], 0); | |
| 232 | + qclose(p->q[0]); | |
| 233 | + } | |
| 234 | + break; | |
| 235 | + case Qdata1: | |
| 236 | + p->qref[1]--; | |
| 237 | + if(p->qref[1] == 0){ | |
| 238 | + qhangup(p->q[0], 0); | |
| 239 | + qclose(p->q[1]); | |
| 240 | + } | |
| 241 | + break; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + | |
| 246 | + /* | |
| 247 | + * if both sides are closed, they are reusable | |
| 248 | + */ | |
| 249 | + if(p->qref[0] == 0 && p->qref[1] == 0){ | |
| 250 | + qreopen(p->q[0]); | |
| 251 | + qreopen(p->q[1]); | |
| 252 | + } | |
| 253 | + | |
| 254 | + /* | |
| 255 | + * free the structure on last close | |
| 256 | + */ | |
| 257 | + p->ref--; | |
| 258 | + if(p->ref == 0){ | |
| 259 | + qunlock(&p->lk); | |
| 260 | + free(p->q[0]); | |
| 261 | + free(p->q[1]); | |
| 262 | + free(p); | |
| 263 | + } else | |
| 264 | + qunlock(&p->lk); | |
| 265 | +} | |
| 266 | + | |
| 267 | +static long | |
| 268 | +piperead(Chan *c, void *va, long n, vlong offset) | |
| 269 | +{ | |
| 270 | + Pipe *p; | |
| 271 | + | |
| 272 | + USED(offset); | |
| 273 | + | |
| 274 | + p = c->aux; | |
| 275 | + | |
| 276 | + switch(NETTYPE(c->qid.path)){ | |
| 277 | + case Qdir: | |
| 278 | + return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen); | |
| 279 | + case Qdata0: | |
| 280 | + return qread(p->q[0], va, n); | |
| 281 | + case Qdata1: | |
| 282 | + return qread(p->q[1], va, n); | |
| 283 | + default: | |
| 284 | + panic("piperead"); | |
| 285 | + } | |
| 286 | + return -1; /* not reached */ | |
| 287 | +} | |
| 288 | + | |
| 289 | +static Block* | |
| 290 | +pipebread(Chan *c, long n, ulong offset) | |
| 291 | +{ | |
| 292 | + Pipe *p; | |
| 293 | + | |
| 294 | + p = c->aux; | |
| 295 | + | |
| 296 | + switch(NETTYPE(c->qid.path)){ | |
| 297 | + case Qdata0: | |
| 298 | + return qbread(p->q[0], n); | |
| 299 | + case Qdata1: | |
| 300 | + return qbread(p->q[1], n); | |
| 301 | + } | |
| 302 | + | |
| 303 | + return devbread(c, n, offset); | |
| 304 | +} | |
| 305 | + | |
| 306 | +/* | |
| 307 | + * a write to a closed pipe causes a note to be sent to | |
| 308 | + * the process. | |
| 309 | + */ | |
| 310 | +static long | |
| 311 | +pipewrite(Chan *c, void *va, long n, vlong offset) | |
| 312 | +{ | |
| 313 | + Pipe *p; | |
| 314 | + | |
| 315 | + USED(offset); | |
| 316 | + if(!islo()) | |
| 317 | + print("pipewrite hi %lux\n", getcallerpc(&c)); | |
| 318 | + | |
| 319 | + if(waserror()) { | |
| 320 | + /* avoid notes when pipe is a mounted queue */ | |
| 321 | + if((c->flag & CMSG) == 0) | |
| 322 | + postnote(up, 1, "sys: write on closed pipe", NUser); | |
| 323 | + nexterror(); | |
| 324 | + } | |
| 325 | + | |
| 326 | + p = c->aux; | |
| 327 | + | |
| 328 | + switch(NETTYPE(c->qid.path)){ | |
| 329 | + case Qdata0: | |
| 330 | + n = qwrite(p->q[1], va, n); | |
| 331 | + break; | |
| 332 | + | |
| 333 | + case Qdata1: | |
| 334 | + n = qwrite(p->q[0], va, n); | |
| 335 | + break; | |
| 336 | + | |
| 337 | + default: | |
| 338 | + panic("pipewrite"); | |
| 339 | + } | |
| 340 | + | |
| 341 | + poperror(); | |
| 342 | + return n; | |
| 343 | +} | |
| 344 | + | |
| 345 | +static long | |
| 346 | +pipebwrite(Chan *c, Block *bp, ulong offset) | |
| 347 | +{ | |
| 348 | + long n; | |
| 349 | + Pipe *p; | |
| 350 | + | |
| 351 | + USED(offset); | |
| 352 | + | |
| 353 | + if(waserror()) { | |
| 354 | + /* avoid notes when pipe is a mounted queue */ | |
| 355 | + if((c->flag & CMSG) == 0) | |
| 356 | + postnote(up, 1, "sys: write on closed pipe", NUser); | |
| 357 | + nexterror(); | |
| 358 | + } | |
| 359 | + | |
| 360 | + p = c->aux; | |
| 361 | + switch(NETTYPE(c->qid.path)){ | |
| 362 | + case Qdata0: | |
| 363 | + n = qbwrite(p->q[1], bp); | |
| 364 | + break; | |
| 365 | + | |
| 366 | + case Qdata1: | |
| 367 | + n = qbwrite(p->q[0], bp); | |
| 368 | + break; | |
| 369 | + | |
| 370 | + default: | |
| 371 | + n = 0; | |
| 372 | + panic("pipebwrite"); | |
| 373 | + } | |
| 374 | + | |
| 375 | + poperror(); | |
| 376 | + return n; | |
| 377 | +} | |
| 378 | + | |
| 379 | +Dev pipedevtab = { | |
| 380 | + '|', | |
| 381 | + "pipe", | |
| 382 | + | |
| 383 | + devreset, | |
| 384 | + pipeinit, | |
| 385 | + devshutdown, | |
| 386 | + pipeattach, | |
| 387 | + pipewalk, | |
| 388 | + pipestat, | |
| 389 | + pipeopen, | |
| 390 | + devcreate, | |
| 391 | + pipeclose, | |
| 392 | + piperead, | |
| 393 | + pipebread, | |
| 394 | + pipewrite, | |
| 395 | + pipebwrite, | |
| 396 | + devremove, | |
| 397 | + devwstat, | |
| 398 | +}; | |
| @@ -0,0 +1,268 @@ | ||
| 1 | +#include "u.h" | |
| 2 | +#include "lib.h" | |
| 3 | +#include "dat.h" | |
| 4 | +#include "fns.h" | |
| 5 | +#include "error.h" | |
| 6 | + | |
| 7 | +enum | |
| 8 | +{ | |
| 9 | + Qdir = 0, | |
| 10 | + Qboot = 0x1000, | |
| 11 | + | |
| 12 | + Nrootfiles = 32, | |
| 13 | + Nbootfiles = 32, | |
| 14 | +}; | |
| 15 | + | |
| 16 | +typedef struct Dirlist Dirlist; | |
| 17 | +struct Dirlist | |
| 18 | +{ | |
| 19 | + uint base; | |
| 20 | + Dirtab *dir; | |
| 21 | + uchar **data; | |
| 22 | + int ndir; | |
| 23 | + int mdir; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +static Dirtab rootdir[Nrootfiles] = { | |
| 27 | + "#/", {Qdir, 0, QTDIR}, 0, DMDIR|0555, | |
| 28 | + "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555, | |
| 29 | +}; | |
| 30 | +static uchar *rootdata[Nrootfiles]; | |
| 31 | +static Dirlist rootlist = | |
| 32 | +{ | |
| 33 | + 0, | |
| 34 | + rootdir, | |
| 35 | + rootdata, | |
| 36 | + 2, | |
| 37 | + Nrootfiles | |
| 38 | +}; | |
| 39 | + | |
| 40 | +static Dirtab bootdir[Nbootfiles] = { | |
| 41 | + "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555, | |
| 42 | +}; | |
| 43 | +static uchar *bootdata[Nbootfiles]; | |
| 44 | +static Dirlist bootlist = | |
| 45 | +{ | |
| 46 | + Qboot, | |
| 47 | + bootdir, | |
| 48 | + bootdata, | |
| 49 | + 1, | |
| 50 | + Nbootfiles | |
| 51 | +}; | |
| 52 | + | |
| 53 | +/* | |
| 54 | + * add a file to the list | |
| 55 | + */ | |
| 56 | +static void | |
| 57 | +addlist(Dirlist *l, char *name, uchar *contents, ulong len, int perm) | |
| 58 | +{ | |
| 59 | + Dirtab *d; | |
| 60 | + | |
| 61 | + if(l->ndir >= l->mdir) | |
| 62 | + panic("too many root files"); | |
| 63 | + l->data[l->ndir] = contents; | |
| 64 | + d = &l->dir[l->ndir]; | |
| 65 | + strcpy(d->name, name); | |
| 66 | + d->length = len; | |
| 67 | + d->perm = perm; | |
| 68 | + d->qid.type = 0; | |
| 69 | + d->qid.vers = 0; | |
| 70 | + d->qid.path = ++l->ndir + l->base; | |
| 71 | + if(perm & DMDIR) | |
| 72 | + d->qid.type |= QTDIR; | |
| 73 | +} | |
| 74 | + | |
| 75 | +/* | |
| 76 | + * add a root file | |
| 77 | + */ | |
| 78 | +void | |
| 79 | +addbootfile(char *name, uchar *contents, ulong len) | |
| 80 | +{ | |
| 81 | + addlist(&bootlist, name, contents, len, 0555); | |
| 82 | +} | |
| 83 | + | |
| 84 | +/* | |
| 85 | + * add a root directory | |
| 86 | + */ | |
| 87 | +static void | |
| 88 | +addrootdir(char *name) | |
| 89 | +{ | |
| 90 | + addlist(&rootlist, name, nil, 0, DMDIR|0555); | |
| 91 | +} | |
| 92 | + | |
| 93 | +static void | |
| 94 | +rootreset(void) | |
| 95 | +{ | |
| 96 | + addrootdir("bin"); | |
| 97 | + addrootdir("dev"); | |
| 98 | + addrootdir("env"); | |
| 99 | + addrootdir("fd"); | |
| 100 | + addrootdir("mnt"); | |
| 101 | + addrootdir("net"); | |
| 102 | + addrootdir("net.alt"); | |
| 103 | + addrootdir("proc"); | |
| 104 | + addrootdir("root"); | |
| 105 | + addrootdir("srv"); | |
| 106 | +} | |
| 107 | + | |
| 108 | +static Chan* | |
| 109 | +rootattach(char *spec) | |
| 110 | +{ | |
| 111 | + return devattach('/', spec); | |
| 112 | +} | |
| 113 | + | |
| 114 | +static int | |
| 115 | +rootgen(Chan *c, char *name, Dirtab *dirt, int ndirt, int s, Dir *dp) | |
| 116 | +{ | |
| 117 | + int t; | |
| 118 | + Dirtab *d; | |
| 119 | + Dirlist *l; | |
| 120 | + | |
| 121 | + USED(dirt); | |
| 122 | + USED(ndirt); | |
| 123 | + | |
| 124 | + switch((int)c->qid.path){ | |
| 125 | + case Qdir: | |
| 126 | + if(s == DEVDOTDOT){ | |
| 127 | + Qid tqiddir = {Qdir, 0, QTDIR}; | |
| 128 | + devdir(c, tqiddir, "#/", 0, eve, 0555, dp); | |
| 129 | + return 1; | |
| 130 | + } | |
| 131 | + return devgen(c, name, rootlist.dir, rootlist.ndir, s, dp); | |
| 132 | + case Qboot: | |
| 133 | + if(s == DEVDOTDOT){ | |
| 134 | + Qid tqiddir = {Qdir, 0, QTDIR}; | |
| 135 | + devdir(c, tqiddir, "#/", 0, eve, 0555, dp); | |
| 136 | + return 1; | |
| 137 | + } | |
| 138 | + return devgen(c, name, bootlist.dir, bootlist.ndir, s, dp); | |
| 139 | + default: | |
| 140 | + if(s == DEVDOTDOT){ | |
| 141 | + Qid tqiddir = {Qdir, 0, QTDIR}; | |
| 142 | + if((int)c->qid.path < Qboot) | |
| 143 | + devdir(c, tqiddir, "#/", 0, eve, 0555, dp); | |
| 144 | + else { | |
| 145 | + tqiddir.path = Qboot; | |
| 146 | + devdir(c, tqiddir, "#/", 0, eve, 0555, dp); | |
| 147 | + } | |
| 148 | + return 1; | |
| 149 | + } | |
| 150 | + if(s != 0) | |
| 151 | + return -1; | |
| 152 | + if((int)c->qid.path < Qboot){ | |
| 153 | + t = c->qid.path-1; | |
| 154 | + l = &rootlist; | |
| 155 | + }else{ | |
| 156 | + t = c->qid.path - Qboot - 1; | |
| 157 | + l = &bootlist; | |
| 158 | + } | |
| 159 | + if(t >= l->ndir) | |
| 160 | + return -1; | |
| 161 | +if(t < 0){ | |
| 162 | +print("rootgen %llud %d %d\n", c->qid.path, s, t); | |
| 163 | +panic("whoops"); | |
| 164 | +} | |
| 165 | + d = &l->dir[t]; | |
| 166 | + devdir(c, d->qid, d->name, d->length, eve, d->perm, dp); | |
| 167 | + return 1; | |
| 168 | + } | |
| 169 | + return -1; | |
| 170 | +} | |
| 171 | + | |
| 172 | +static Walkqid* | |
| 173 | +rootwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 174 | +{ | |
| 175 | + return devwalk(c, nc, name, nname, nil, 0, rootgen); | |
| 176 | +} | |
| 177 | + | |
| 178 | +static int | |
| 179 | +rootstat(Chan *c, uchar *dp, int n) | |
| 180 | +{ | |
| 181 | + return devstat(c, dp, n, nil, 0, rootgen); | |
| 182 | +} | |
| 183 | + | |
| 184 | +static Chan* | |
| 185 | +rootopen(Chan *c, int omode) | |
| 186 | +{ | |
| 187 | + return devopen(c, omode, nil, 0, devgen); | |
| 188 | +} | |
| 189 | + | |
| 190 | +/* | |
| 191 | + * sysremove() knows this is a nop | |
| 192 | + */ | |
| 193 | +static void | |
| 194 | +rootclose(Chan *c) | |
| 195 | +{ | |
| 196 | + USED(c); | |
| 197 | +} | |
| 198 | + | |
| 199 | +static long | |
| 200 | +rootread(Chan *c, void *buf, long n, vlong off) | |
| 201 | +{ | |
| 202 | + ulong t; | |
| 203 | + Dirtab *d; | |
| 204 | + Dirlist *l; | |
| 205 | + uchar *data; | |
| 206 | + ulong offset = off; | |
| 207 | + | |
| 208 | + t = c->qid.path; | |
| 209 | + switch(t){ | |
| 210 | + case Qdir: | |
| 211 | + case Qboot: | |
| 212 | + return devdirread(c, buf, n, nil, 0, rootgen); | |
| 213 | + } | |
| 214 | + | |
| 215 | + if(t<Qboot) | |
| 216 | + l = &rootlist; | |
| 217 | + else{ | |
| 218 | + t -= Qboot; | |
| 219 | + l = &bootlist; | |
| 220 | + } | |
| 221 | + | |
| 222 | + t--; | |
| 223 | + if(t >= l->ndir) | |
| 224 | + error(Egreg); | |
| 225 | + | |
| 226 | + d = &l->dir[t]; | |
| 227 | + data = l->data[t]; | |
| 228 | + if(offset >= d->length) | |
| 229 | + return 0; | |
| 230 | + if(offset+n > d->length) | |
| 231 | + n = d->length - offset; | |
| 232 | + memmove(buf, data+offset, n); | |
| 233 | + return n; | |
| 234 | +} | |
| 235 | + | |
| 236 | +static long | |
| 237 | +rootwrite(Chan *c, void *v, long n, vlong o) | |
| 238 | +{ | |
| 239 | + USED(c); | |
| 240 | + USED(v); | |
| 241 | + USED(n); | |
| 242 | + USED(o); | |
| 243 | + | |
| 244 | + error(Egreg); | |
| 245 | + return 0; | |
| 246 | +} | |
| 247 | + | |
| 248 | +Dev rootdevtab = { | |
| 249 | + '/', | |
| 250 | + "root", | |
| 251 | + | |
| 252 | + rootreset, | |
| 253 | + devinit, | |
| 254 | + devshutdown, | |
| 255 | + rootattach, | |
| 256 | + rootwalk, | |
| 257 | + rootstat, | |
| 258 | + rootopen, | |
| 259 | + devcreate, | |
| 260 | + rootclose, | |
| 261 | + rootread, | |
| 262 | + devbread, | |
| 263 | + rootwrite, | |
| 264 | + devbwrite, | |
| 265 | + devremove, | |
| 266 | + devwstat, | |
| 267 | +}; | |
| 268 | + | |
| @@ -0,0 +1,1512 @@ | ||
| 1 | +/* | |
| 2 | + * devssl - secure sockets layer | |
| 3 | + */ | |
| 4 | +#include "u.h" | |
| 5 | +#include "lib.h" | |
| 6 | +#include "dat.h" | |
| 7 | +#include "fns.h" | |
| 8 | +#include "error.h" | |
| 9 | + | |
| 10 | +#include "libsec.h" | |
| 11 | + | |
| 12 | +#define NOSPOOKS 1 | |
| 13 | + | |
| 14 | +typedef struct OneWay OneWay; | |
| 15 | +struct OneWay | |
| 16 | +{ | |
| 17 | + QLock q; | |
| 18 | + QLock ctlq; | |
| 19 | + | |
| 20 | + void *state; /* encryption state */ | |
| 21 | + int slen; /* hash data length */ | |
| 22 | + uchar *secret; /* secret */ | |
| 23 | + ulong mid; /* message id */ | |
| 24 | +}; | |
| 25 | + | |
| 26 | +enum | |
| 27 | +{ | |
| 28 | + /* connection states */ | |
| 29 | + Sincomplete= 0, | |
| 30 | + Sclear= 1, | |
| 31 | + Sencrypting= 2, | |
| 32 | + Sdigesting= 4, | |
| 33 | + Sdigenc= Sencrypting|Sdigesting, | |
| 34 | + | |
| 35 | + /* encryption algorithms */ | |
| 36 | + Noencryption= 0, | |
| 37 | + DESCBC= 1, | |
| 38 | + DESECB= 2, | |
| 39 | + RC4= 3 | |
| 40 | +}; | |
| 41 | + | |
| 42 | +typedef struct Dstate Dstate; | |
| 43 | +struct Dstate | |
| 44 | +{ | |
| 45 | + Chan *c; /* io channel */ | |
| 46 | + uchar state; /* state of connection */ | |
| 47 | + int ref; /* serialized by dslock for atomic destroy */ | |
| 48 | + | |
| 49 | + uchar encryptalg; /* encryption algorithm */ | |
| 50 | + ushort blocklen; /* blocking length */ | |
| 51 | + | |
| 52 | + ushort diglen; /* length of digest */ | |
| 53 | + DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */ | |
| 54 | + | |
| 55 | + /* for SSL format */ | |
| 56 | + int max; /* maximum unpadded data per msg */ | |
| 57 | + int maxpad; /* maximum padded data per msg */ | |
| 58 | + | |
| 59 | + /* input side */ | |
| 60 | + OneWay in; | |
| 61 | + Block *processed; | |
| 62 | + Block *unprocessed; | |
| 63 | + | |
| 64 | + /* output side */ | |
| 65 | + OneWay out; | |
| 66 | + | |
| 67 | + /* protections */ | |
| 68 | + char *user; | |
| 69 | + int perm; | |
| 70 | +}; | |
| 71 | + | |
| 72 | +enum | |
| 73 | +{ | |
| 74 | + Maxdmsg= 1<<16, | |
| 75 | + Maxdstate= 128, /* must be a power of 2 */ | |
| 76 | +}; | |
| 77 | + | |
| 78 | +Lock dslock; | |
| 79 | +int dshiwat; | |
| 80 | +char *dsname[Maxdstate]; | |
| 81 | +Dstate *dstate[Maxdstate]; | |
| 82 | +char *encalgs; | |
| 83 | +char *hashalgs; | |
| 84 | + | |
| 85 | +enum{ | |
| 86 | + Qtopdir = 1, /* top level directory */ | |
| 87 | + Qprotodir, | |
| 88 | + Qclonus, | |
| 89 | + Qconvdir, /* directory for a conversation */ | |
| 90 | + Qdata, | |
| 91 | + Qctl, | |
| 92 | + Qsecretin, | |
| 93 | + Qsecretout, | |
| 94 | + Qencalgs, | |
| 95 | + Qhashalgs, | |
| 96 | +}; | |
| 97 | + | |
| 98 | +#define TYPE(x) ((x).path & 0xf) | |
| 99 | +#define CONV(x) (((x).path >> 5)&(Maxdstate-1)) | |
| 100 | +#define QID(c, y) (((c)<<5) | (y)) | |
| 101 | + | |
| 102 | +static void ensure(Dstate*, Block**, int); | |
| 103 | +static void consume(Block**, uchar*, int); | |
| 104 | +static void setsecret(OneWay*, uchar*, int); | |
| 105 | +static Block* encryptb(Dstate*, Block*, int); | |
| 106 | +static Block* decryptb(Dstate*, Block*); | |
| 107 | +static Block* digestb(Dstate*, Block*, int); | |
| 108 | +static void checkdigestb(Dstate*, Block*); | |
| 109 | +static Chan* buftochan(char*); | |
| 110 | +static void sslhangup(Dstate*); | |
| 111 | +static Dstate* dsclone(Chan *c); | |
| 112 | +static void dsnew(Chan *c, Dstate **); | |
| 113 | +static long sslput(Dstate *s, Block * volatile b); | |
| 114 | + | |
| 115 | +char *sslnames[] = { | |
| 116 | + /* unused */ 0, | |
| 117 | + /* topdir */ 0, | |
| 118 | + /* protodir */ 0, | |
| 119 | + "clone", | |
| 120 | + /* convdir */ 0, | |
| 121 | + "data", | |
| 122 | + "ctl", | |
| 123 | + "secretin", | |
| 124 | + "secretout", | |
| 125 | + "encalgs", | |
| 126 | + "hashalgs", | |
| 127 | +}; | |
| 128 | + | |
| 129 | +static int | |
| 130 | +sslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp) | |
| 131 | +{ | |
| 132 | + Qid q; | |
| 133 | + Dstate *ds; | |
| 134 | + char name[16], *p, *nm; | |
| 135 | + int ft; | |
| 136 | + | |
| 137 | + USED(n); | |
| 138 | + USED(nd); | |
| 139 | + USED(d); | |
| 140 | + | |
| 141 | + q.type = QTFILE; | |
| 142 | + q.vers = 0; | |
| 143 | + | |
| 144 | + ft = TYPE(c->qid); | |
| 145 | + switch(ft) { | |
| 146 | + case Qtopdir: | |
| 147 | + if(s == DEVDOTDOT){ | |
| 148 | + q.path = QID(0, Qtopdir); | |
| 149 | + q.type = QTDIR; | |
| 150 | + devdir(c, q, "#D", 0, eve, 0555, dp); | |
| 151 | + return 1; | |
| 152 | + } | |
| 153 | + if(s > 0) | |
| 154 | + return -1; | |
| 155 | + q.path = QID(0, Qprotodir); | |
| 156 | + q.type = QTDIR; | |
| 157 | + devdir(c, q, "ssl", 0, eve, 0555, dp); | |
| 158 | + return 1; | |
| 159 | + case Qprotodir: | |
| 160 | + if(s == DEVDOTDOT){ | |
| 161 | + q.path = QID(0, Qtopdir); | |
| 162 | + q.type = QTDIR; | |
| 163 | + devdir(c, q, ".", 0, eve, 0555, dp); | |
| 164 | + return 1; | |
| 165 | + } | |
| 166 | + if(s < dshiwat) { | |
| 167 | + q.path = QID(s, Qconvdir); | |
| 168 | + q.type = QTDIR; | |
| 169 | + ds = dstate[s]; | |
| 170 | + if(ds != 0) | |
| 171 | + nm = ds->user; | |
| 172 | + else | |
| 173 | + nm = eve; | |
| 174 | + if(dsname[s] == nil){ | |
| 175 | + sprint(name, "%d", s); | |
| 176 | + kstrdup(&dsname[s], name); | |
| 177 | + } | |
| 178 | + devdir(c, q, dsname[s], 0, nm, 0555, dp); | |
| 179 | + return 1; | |
| 180 | + } | |
| 181 | + if(s > dshiwat) | |
| 182 | + return -1; | |
| 183 | + q.path = QID(0, Qclonus); | |
| 184 | + devdir(c, q, "clone", 0, eve, 0555, dp); | |
| 185 | + return 1; | |
| 186 | + case Qconvdir: | |
| 187 | + if(s == DEVDOTDOT){ | |
| 188 | + q.path = QID(0, Qprotodir); | |
| 189 | + q.type = QTDIR; | |
| 190 | + devdir(c, q, "ssl", 0, eve, 0555, dp); | |
| 191 | + return 1; | |
| 192 | + } | |
| 193 | + ds = dstate[CONV(c->qid)]; | |
| 194 | + if(ds != 0) | |
| 195 | + nm = ds->user; | |
| 196 | + else | |
| 197 | + nm = eve; | |
| 198 | + switch(s) { | |
| 199 | + default: | |
| 200 | + return -1; | |
| 201 | + case 0: | |
| 202 | + q.path = QID(CONV(c->qid), Qctl); | |
| 203 | + p = "ctl"; | |
| 204 | + break; | |
| 205 | + case 1: | |
| 206 | + q.path = QID(CONV(c->qid), Qdata); | |
| 207 | + p = "data"; | |
| 208 | + break; | |
| 209 | + case 2: | |
| 210 | + q.path = QID(CONV(c->qid), Qsecretin); | |
| 211 | + p = "secretin"; | |
| 212 | + break; | |
| 213 | + case 3: | |
| 214 | + q.path = QID(CONV(c->qid), Qsecretout); | |
| 215 | + p = "secretout"; | |
| 216 | + break; | |
| 217 | + case 4: | |
| 218 | + q.path = QID(CONV(c->qid), Qencalgs); | |
| 219 | + p = "encalgs"; | |
| 220 | + break; | |
| 221 | + case 5: | |
| 222 | + q.path = QID(CONV(c->qid), Qhashalgs); | |
| 223 | + p = "hashalgs"; | |
| 224 | + break; | |
| 225 | + } | |
| 226 | + devdir(c, q, p, 0, nm, 0660, dp); | |
| 227 | + return 1; | |
| 228 | + case Qclonus: | |
| 229 | + devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp); | |
| 230 | + return 1; | |
| 231 | + default: | |
| 232 | + ds = dstate[CONV(c->qid)]; | |
| 233 | + if(ds != 0) | |
| 234 | + nm = ds->user; | |
| 235 | + else | |
| 236 | + nm = eve; | |
| 237 | + devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp); | |
| 238 | + return 1; | |
| 239 | + } | |
| 240 | + return -1; | |
| 241 | +} | |
| 242 | + | |
| 243 | +static Chan* | |
| 244 | +sslattach(char *spec) | |
| 245 | +{ | |
| 246 | + Chan *c; | |
| 247 | + | |
| 248 | + c = devattach('D', spec); | |
| 249 | + c->qid.path = QID(0, Qtopdir); | |
| 250 | + c->qid.vers = 0; | |
| 251 | + c->qid.type = QTDIR; | |
| 252 | + return c; | |
| 253 | +} | |
| 254 | + | |
| 255 | +static Walkqid* | |
| 256 | +sslwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 257 | +{ | |
| 258 | + return devwalk(c, nc, name, nname, nil, 0, sslgen); | |
| 259 | +} | |
| 260 | + | |
| 261 | +static int | |
| 262 | +sslstat(Chan *c, uchar *db, int n) | |
| 263 | +{ | |
| 264 | + return devstat(c, db, n, nil, 0, sslgen); | |
| 265 | +} | |
| 266 | + | |
| 267 | +static Chan* | |
| 268 | +sslopen(Chan *c, int omode) | |
| 269 | +{ | |
| 270 | + Dstate *s, **pp; | |
| 271 | + int perm; | |
| 272 | + int ft; | |
| 273 | + | |
| 274 | + perm = 0; | |
| 275 | + omode &= 3; | |
| 276 | + switch(omode) { | |
| 277 | + case OREAD: | |
| 278 | + perm = 4; | |
| 279 | + break; | |
| 280 | + case OWRITE: | |
| 281 | + perm = 2; | |
| 282 | + break; | |
| 283 | + case ORDWR: | |
| 284 | + perm = 6; | |
| 285 | + break; | |
| 286 | + } | |
| 287 | + | |
| 288 | + ft = TYPE(c->qid); | |
| 289 | + switch(ft) { | |
| 290 | + default: | |
| 291 | + panic("sslopen"); | |
| 292 | + case Qtopdir: | |
| 293 | + case Qprotodir: | |
| 294 | + case Qconvdir: | |
| 295 | + if(omode != OREAD) | |
| 296 | + error(Eperm); | |
| 297 | + break; | |
| 298 | + case Qclonus: | |
| 299 | + s = dsclone(c); | |
| 300 | + if(s == 0) | |
| 301 | + error(Enodev); | |
| 302 | + break; | |
| 303 | + case Qctl: | |
| 304 | + case Qdata: | |
| 305 | + case Qsecretin: | |
| 306 | + case Qsecretout: | |
| 307 | + if(waserror()) { | |
| 308 | + unlock(&dslock); | |
| 309 | + nexterror(); | |
| 310 | + } | |
| 311 | + lock(&dslock); | |
| 312 | + pp = &dstate[CONV(c->qid)]; | |
| 313 | + s = *pp; | |
| 314 | + if(s == 0) | |
| 315 | + dsnew(c, pp); | |
| 316 | + else { | |
| 317 | + if((perm & (s->perm>>6)) != perm | |
| 318 | + && (strcmp(up->user, s->user) != 0 | |
| 319 | + || (perm & s->perm) != perm)) | |
| 320 | + error(Eperm); | |
| 321 | + | |
| 322 | + s->ref++; | |
| 323 | + } | |
| 324 | + unlock(&dslock); | |
| 325 | + poperror(); | |
| 326 | + break; | |
| 327 | + case Qencalgs: | |
| 328 | + case Qhashalgs: | |
| 329 | + if(omode != OREAD) | |
| 330 | + error(Eperm); | |
| 331 | + break; | |
| 332 | + } | |
| 333 | + c->mode = openmode(omode); | |
| 334 | + c->flag |= COPEN; | |
| 335 | + c->offset = 0; | |
| 336 | + return c; | |
| 337 | +} | |
| 338 | + | |
| 339 | +static int | |
| 340 | +sslwstat(Chan *c, uchar *db, int n) | |
| 341 | +{ | |
| 342 | + Dir *dir; | |
| 343 | + Dstate *s; | |
| 344 | + int m; | |
| 345 | + | |
| 346 | + s = dstate[CONV(c->qid)]; | |
| 347 | + if(s == 0) | |
| 348 | + error(Ebadusefd); | |
| 349 | + if(strcmp(s->user, up->user) != 0) | |
| 350 | + error(Eperm); | |
| 351 | + | |
| 352 | + dir = smalloc(sizeof(Dir)+n); | |
| 353 | + m = convM2D(db, n, &dir[0], (char*)&dir[1]); | |
| 354 | + if(m == 0){ | |
| 355 | + free(dir); | |
| 356 | + error(Eshortstat); | |
| 357 | + } | |
| 358 | + | |
| 359 | + if(!emptystr(dir->uid)) | |
| 360 | + kstrdup(&s->user, dir->uid); | |
| 361 | + if(dir->mode != ~0UL) | |
| 362 | + s->perm = dir->mode; | |
| 363 | + | |
| 364 | + free(dir); | |
| 365 | + return m; | |
| 366 | +} | |
| 367 | + | |
| 368 | +static void | |
| 369 | +sslclose(Chan *c) | |
| 370 | +{ | |
| 371 | + Dstate *s; | |
| 372 | + int ft; | |
| 373 | + | |
| 374 | + ft = TYPE(c->qid); | |
| 375 | + switch(ft) { | |
| 376 | + case Qctl: | |
| 377 | + case Qdata: | |
| 378 | + case Qsecretin: | |
| 379 | + case Qsecretout: | |
| 380 | + if((c->flag & COPEN) == 0) | |
| 381 | + break; | |
| 382 | + | |
| 383 | + s = dstate[CONV(c->qid)]; | |
| 384 | + if(s == 0) | |
| 385 | + break; | |
| 386 | + | |
| 387 | + lock(&dslock); | |
| 388 | + if(--s->ref > 0) { | |
| 389 | + unlock(&dslock); | |
| 390 | + break; | |
| 391 | + } | |
| 392 | + dstate[CONV(c->qid)] = 0; | |
| 393 | + unlock(&dslock); | |
| 394 | + | |
| 395 | + if(s->user != nil) | |
| 396 | + free(s->user); | |
| 397 | + sslhangup(s); | |
| 398 | + if(s->c) | |
| 399 | + cclose(s->c); | |
| 400 | + if(s->in.secret) | |
| 401 | + free(s->in.secret); | |
| 402 | + if(s->out.secret) | |
| 403 | + free(s->out.secret); | |
| 404 | + if(s->in.state) | |
| 405 | + free(s->in.state); | |
| 406 | + if(s->out.state) | |
| 407 | + free(s->out.state); | |
| 408 | + free(s); | |
| 409 | + | |
| 410 | + } | |
| 411 | +} | |
| 412 | + | |
| 413 | +/* | |
| 414 | + * make sure we have at least 'n' bytes in list 'l' | |
| 415 | + */ | |
| 416 | +static void | |
| 417 | +ensure(Dstate *s, Block **l, int n) | |
| 418 | +{ | |
| 419 | + int sofar, i; | |
| 420 | + Block *b, *bl; | |
| 421 | + | |
| 422 | + sofar = 0; | |
| 423 | + for(b = *l; b; b = b->next){ | |
| 424 | + sofar += BLEN(b); | |
| 425 | + if(sofar >= n) | |
| 426 | + return; | |
| 427 | + l = &b->next; | |
| 428 | + } | |
| 429 | + | |
| 430 | + while(sofar < n){ | |
| 431 | + bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0); | |
| 432 | + if(bl == 0) | |
| 433 | + nexterror(); | |
| 434 | + *l = bl; | |
| 435 | + i = 0; | |
| 436 | + for(b = bl; b; b = b->next){ | |
| 437 | + i += BLEN(b); | |
| 438 | + l = &b->next; | |
| 439 | + } | |
| 440 | + if(i == 0) | |
| 441 | + error(Ehungup); | |
| 442 | + sofar += i; | |
| 443 | + } | |
| 444 | +} | |
| 445 | + | |
| 446 | +/* | |
| 447 | + * copy 'n' bytes from 'l' into 'p' and free | |
| 448 | + * the bytes in 'l' | |
| 449 | + */ | |
| 450 | +static void | |
| 451 | +consume(Block **l, uchar *p, int n) | |
| 452 | +{ | |
| 453 | + Block *b; | |
| 454 | + int i; | |
| 455 | + | |
| 456 | + for(; *l && n > 0; n -= i){ | |
| 457 | + b = *l; | |
| 458 | + i = BLEN(b); | |
| 459 | + if(i > n) | |
| 460 | + i = n; | |
| 461 | + memmove(p, b->rp, i); | |
| 462 | + b->rp += i; | |
| 463 | + p += i; | |
| 464 | + if(BLEN(b) < 0) | |
| 465 | + panic("consume"); | |
| 466 | + if(BLEN(b)) | |
| 467 | + break; | |
| 468 | + *l = b->next; | |
| 469 | + freeb(b); | |
| 470 | + } | |
| 471 | +} | |
| 472 | + | |
| 473 | +/* | |
| 474 | + * give back n bytes | |
| 475 | +static void | |
| 476 | +regurgitate(Dstate *s, uchar *p, int n) | |
| 477 | +{ | |
| 478 | + Block *b; | |
| 479 | + | |
| 480 | + if(n <= 0) | |
| 481 | + return; | |
| 482 | + b = s->unprocessed; | |
| 483 | + if(s->unprocessed == nil || b->rp - b->base < n) { | |
| 484 | + b = allocb(n); | |
| 485 | + memmove(b->wp, p, n); | |
| 486 | + b->wp += n; | |
| 487 | + b->next = s->unprocessed; | |
| 488 | + s->unprocessed = b; | |
| 489 | + } else { | |
| 490 | + b->rp -= n; | |
| 491 | + memmove(b->rp, p, n); | |
| 492 | + } | |
| 493 | +} | |
| 494 | + */ | |
| 495 | + | |
| 496 | +/* | |
| 497 | + * remove at most n bytes from the queue, if discard is set | |
| 498 | + * dump the remainder | |
| 499 | + */ | |
| 500 | +static Block* | |
| 501 | +qtake(Block **l, int n, int discard) | |
| 502 | +{ | |
| 503 | + Block *nb, *b, *first; | |
| 504 | + int i; | |
| 505 | + | |
| 506 | + first = *l; | |
| 507 | + for(b = first; b; b = b->next){ | |
| 508 | + i = BLEN(b); | |
| 509 | + if(i == n){ | |
| 510 | + if(discard){ | |
| 511 | + freeblist(b->next); | |
| 512 | + *l = 0; | |
| 513 | + } else | |
| 514 | + *l = b->next; | |
| 515 | + b->next = 0; | |
| 516 | + return first; | |
| 517 | + } else if(i > n){ | |
| 518 | + i -= n; | |
| 519 | + if(discard){ | |
| 520 | + freeblist(b->next); | |
| 521 | + b->wp -= i; | |
| 522 | + *l = 0; | |
| 523 | + } else { | |
| 524 | + nb = allocb(i); | |
| 525 | + memmove(nb->wp, b->rp+n, i); | |
| 526 | + nb->wp += i; | |
| 527 | + b->wp -= i; | |
| 528 | + nb->next = b->next; | |
| 529 | + *l = nb; | |
| 530 | + } | |
| 531 | + b->next = 0; | |
| 532 | + if(BLEN(b) < 0) | |
| 533 | + panic("qtake"); | |
| 534 | + return first; | |
| 535 | + } else | |
| 536 | + n -= i; | |
| 537 | + if(BLEN(b) < 0) | |
| 538 | + panic("qtake"); | |
| 539 | + } | |
| 540 | + *l = 0; | |
| 541 | + return first; | |
| 542 | +} | |
| 543 | + | |
| 544 | +/* | |
| 545 | + * We can't let Eintr's lose data since the program | |
| 546 | + * doing the read may be able to handle it. The only | |
| 547 | + * places Eintr is possible is during the read's in consume. | |
| 548 | + * Therefore, we make sure we can always put back the bytes | |
| 549 | + * consumed before the last ensure. | |
| 550 | + */ | |
| 551 | +static Block* | |
| 552 | +sslbread(Chan *c, long n, ulong o) | |
| 553 | +{ | |
| 554 | + Dstate * volatile s; | |
| 555 | + Block *b; | |
| 556 | + uchar consumed[3], *p; | |
| 557 | + int toconsume; | |
| 558 | + int len, pad; | |
| 559 | + | |
| 560 | + USED(o); | |
| 561 | + s = dstate[CONV(c->qid)]; | |
| 562 | + if(s == 0) | |
| 563 | + panic("sslbread"); | |
| 564 | + if(s->state == Sincomplete) | |
| 565 | + error(Ebadusefd); | |
| 566 | + | |
| 567 | + qlock(&s->in.q); | |
| 568 | + if(waserror()){ | |
| 569 | + qunlock(&s->in.q); | |
| 570 | + nexterror(); | |
| 571 | + } | |
| 572 | + | |
| 573 | + if(s->processed == 0){ | |
| 574 | + /* | |
| 575 | + * Read in the whole message. Until we've got it all, | |
| 576 | + * it stays on s->unprocessed, so that if we get Eintr, | |
| 577 | + * we'll pick up where we left off. | |
| 578 | + */ | |
| 579 | + ensure(s, &s->unprocessed, 3); | |
| 580 | + s->unprocessed = pullupblock(s->unprocessed, 2); | |
| 581 | + p = s->unprocessed->rp; | |
| 582 | + if(p[0] & 0x80){ | |
| 583 | + len = ((p[0] & 0x7f)<<8) | p[1]; | |
| 584 | + ensure(s, &s->unprocessed, len); | |
| 585 | + pad = 0; | |
| 586 | + toconsume = 2; | |
| 587 | + } else { | |
| 588 | + s->unprocessed = pullupblock(s->unprocessed, 3); | |
| 589 | + len = ((p[0] & 0x3f)<<8) | p[1]; | |
| 590 | + pad = p[2]; | |
| 591 | + if(pad > len){ | |
| 592 | + print("pad %d buf len %d\n", pad, len); | |
| 593 | + error("bad pad in ssl message"); | |
| 594 | + } | |
| 595 | + toconsume = 3; | |
| 596 | + } | |
| 597 | + ensure(s, &s->unprocessed, toconsume+len); | |
| 598 | + | |
| 599 | + /* skip header */ | |
| 600 | + consume(&s->unprocessed, consumed, toconsume); | |
| 601 | + | |
| 602 | + /* grab the next message and decode/decrypt it */ | |
| 603 | + b = qtake(&s->unprocessed, len, 0); | |
| 604 | + | |
| 605 | + if(blocklen(b) != len) | |
| 606 | + print("devssl: sslbread got wrong count %d != %d", blocklen(b), len); | |
| 607 | + | |
| 608 | + if(waserror()){ | |
| 609 | + qunlock(&s->in.ctlq); | |
| 610 | + if(b != nil) | |
| 611 | + freeb(b); | |
| 612 | + nexterror(); | |
| 613 | + } | |
| 614 | + qlock(&s->in.ctlq); | |
| 615 | + switch(s->state){ | |
| 616 | + case Sencrypting: | |
| 617 | + if(b == nil) | |
| 618 | + error("ssl message too short (encrypting)"); | |
| 619 | + b = decryptb(s, b); | |
| 620 | + break; | |
| 621 | + case Sdigesting: | |
| 622 | + b = pullupblock(b, s->diglen); | |
| 623 | + if(b == nil) | |
| 624 | + error("ssl message too short (digesting)"); | |
| 625 | + checkdigestb(s, b); | |
| 626 | + b->rp += s->diglen; | |
| 627 | + break; | |
| 628 | + case Sdigenc: | |
| 629 | + b = decryptb(s, b); | |
| 630 | + b = pullupblock(b, s->diglen); | |
| 631 | + if(b == nil) | |
| 632 | + error("ssl message too short (dig+enc)"); | |
| 633 | + checkdigestb(s, b); | |
| 634 | + b->rp += s->diglen; | |
| 635 | + len -= s->diglen; | |
| 636 | + break; | |
| 637 | + } | |
| 638 | + | |
| 639 | + /* remove pad */ | |
| 640 | + if(pad) | |
| 641 | + s->processed = qtake(&b, len - pad, 1); | |
| 642 | + else | |
| 643 | + s->processed = b; | |
| 644 | + b = nil; | |
| 645 | + s->in.mid++; | |
| 646 | + qunlock(&s->in.ctlq); | |
| 647 | + poperror(); | |
| 648 | + } | |
| 649 | + | |
| 650 | + /* return at most what was asked for */ | |
| 651 | + b = qtake(&s->processed, n, 0); | |
| 652 | + | |
| 653 | + qunlock(&s->in.q); | |
| 654 | + poperror(); | |
| 655 | + | |
| 656 | + return b; | |
| 657 | +} | |
| 658 | + | |
| 659 | +static long | |
| 660 | +sslread(Chan *c, void *a, long n, vlong off) | |
| 661 | +{ | |
| 662 | + Block * volatile b; | |
| 663 | + Block *nb; | |
| 664 | + uchar *va; | |
| 665 | + int i; | |
| 666 | + char buf[128]; | |
| 667 | + ulong offset = off; | |
| 668 | + int ft; | |
| 669 | + | |
| 670 | + if(c->qid.type & QTDIR) | |
| 671 | + return devdirread(c, a, n, 0, 0, sslgen); | |
| 672 | + | |
| 673 | + ft = TYPE(c->qid); | |
| 674 | + switch(ft) { | |
| 675 | + default: | |
| 676 | + error(Ebadusefd); | |
| 677 | + case Qctl: | |
| 678 | + ft = CONV(c->qid); | |
| 679 | + sprint(buf, "%d", ft); | |
| 680 | + return readstr(offset, a, n, buf); | |
| 681 | + case Qdata: | |
| 682 | + b = sslbread(c, n, offset); | |
| 683 | + break; | |
| 684 | + case Qencalgs: | |
| 685 | + return readstr(offset, a, n, encalgs); | |
| 686 | + break; | |
| 687 | + case Qhashalgs: | |
| 688 | + return readstr(offset, a, n, hashalgs); | |
| 689 | + break; | |
| 690 | + } | |
| 691 | + | |
| 692 | + if(waserror()){ | |
| 693 | + freeblist(b); | |
| 694 | + nexterror(); | |
| 695 | + } | |
| 696 | + | |
| 697 | + n = 0; | |
| 698 | + va = a; | |
| 699 | + for(nb = b; nb; nb = nb->next){ | |
| 700 | + i = BLEN(nb); | |
| 701 | + memmove(va+n, nb->rp, i); | |
| 702 | + n += i; | |
| 703 | + } | |
| 704 | + | |
| 705 | + freeblist(b); | |
| 706 | + poperror(); | |
| 707 | + | |
| 708 | + return n; | |
| 709 | +} | |
| 710 | + | |
| 711 | +/* | |
| 712 | + * this algorithm doesn't have to be great since we're just | |
| 713 | + * trying to obscure the block fill | |
| 714 | + */ | |
| 715 | +static void | |
| 716 | +randfill(uchar *buf, int len) | |
| 717 | +{ | |
| 718 | + while(len-- > 0) | |
| 719 | + *buf++ = nrand(256); | |
| 720 | +} | |
| 721 | + | |
| 722 | +static long | |
| 723 | +sslbwrite(Chan *c, Block *b, ulong o) | |
| 724 | +{ | |
| 725 | + Dstate * volatile s; | |
| 726 | + long rv; | |
| 727 | + | |
| 728 | + USED(o); | |
| 729 | + s = dstate[CONV(c->qid)]; | |
| 730 | + if(s == nil) | |
| 731 | + panic("sslbwrite"); | |
| 732 | + | |
| 733 | + if(s->state == Sincomplete){ | |
| 734 | + freeb(b); | |
| 735 | + error(Ebadusefd); | |
| 736 | + } | |
| 737 | + | |
| 738 | + /* lock so split writes won't interleave */ | |
| 739 | + if(waserror()){ | |
| 740 | + qunlock(&s->out.q); | |
| 741 | + nexterror(); | |
| 742 | + } | |
| 743 | + qlock(&s->out.q); | |
| 744 | + | |
| 745 | + rv = sslput(s, b); | |
| 746 | + | |
| 747 | + poperror(); | |
| 748 | + qunlock(&s->out.q); | |
| 749 | + | |
| 750 | + return rv; | |
| 751 | +} | |
| 752 | + | |
| 753 | +/* | |
| 754 | + * use SSL record format, add in count, digest and/or encrypt. | |
| 755 | + * the write is interruptable. if it is interrupted, we'll | |
| 756 | + * get out of sync with the far side. not much we can do about | |
| 757 | + * it since we don't know if any bytes have been written. | |
| 758 | + */ | |
| 759 | +static long | |
| 760 | +sslput(Dstate *s, Block * volatile b) | |
| 761 | +{ | |
| 762 | + Block *nb; | |
| 763 | + int h, n, m, pad, rv; | |
| 764 | + uchar *p; | |
| 765 | + int offset; | |
| 766 | + | |
| 767 | + if(waserror()){ | |
| 768 | + if(b != nil) | |
744 more lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 822 lines aren’t shown here.
This diff is large: its 378 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 185 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 273 lines aren’t shown here.
This diff is large: its 191 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 1525 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 171 lines aren’t shown here.
This diff is large: its 838 lines aren’t shown here.
This diff is large: its 1243 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
Empty file added.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 602 lines aren’t shown here.
This diff is large: its 178 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 369 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 316 lines aren’t shown here.
This diff is large: its 387 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 521 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 313 lines aren’t shown here.
This diff is large: its 194 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 248 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 1139 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 533 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 403 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 262 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 321 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 2500 lines aren’t shown here.
This diff is large: its 1005 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 524 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 486 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 193 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 194 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 1545 lines aren’t shown here.
This diff is large: its 580 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 481 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 272 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 149 lines aren’t shown here.
This diff is large: its 268 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
Binary file not shown.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 128 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 1005 lines aren’t shown here.
This diff is large: its 1040 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 2292 lines aren’t shown here.
This diff is large: its 2521 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 668 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.