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.