History

a

Russ Cox committed 21 years ago

Commit 934846f1 parent 0189e66382 files · +62610 −-4Browse files

Unified · Split

382 files
  1. Makefile +82 −0
  2. Notes +16 −0
  3. args.h +20 −0
  4. cpu.c +606 −0
  5. drawterm.h +10 −0
  6. drawterm.ico +0 −0
  7. drawterm.rc +72 −0
  8. drawterm.res +0 −0
  9. exportfs/Makefile +16 −0
  10. exportfs/exportfs.c +503 −0
  11. exportfs/exportfs.h +148 −0
  12. exportfs/exportsrv.c +679 −0
  13. exportfs/mkfile +11 −0
  14. gui-win32/alloc.c +23 −0
  15. gui-win32/cload.c +10 −0
  16. gui-win32/draw.c +22 −0
  17. gui-win32/load.c +10 −0
  18. gui-win32/mkfile +14 −0
  19. gui-win32/screen.c +642 −0
  20. gui-win32/wstrtoutf.c +35 −0
  21. gui-x11/Makefile +20 −0
  22. gui-x11/alloc.c +209 −0
  23. gui-x11/cload.c +16 −0
  24. gui-x11/draw.c +189 −0
  25. gui-x11/keysym2ucs-x11.c +857 −0
  26. gui-x11/keysym2ucs.h +9 −0
  27. gui-x11/ksym2utf.h +754 −0
  28. gui-x11/load.c +16 −0
  29. gui-x11/screen.c +1094 −0
  30. gui-x11/xmem.h +60 −0
  31. include/a.out +0 −0
  32. include/auth.h +144 −0
  33. include/authsrv.h +166 −0
  34. include/cursor.h +6 −0
  35. include/draw.h +519 −0
  36. include/dtos.h +10 −0
  37. include/fcall.h +110 −0
  38. include/keyboard.h +42 −0
  39. include/lib.h +246 −0
  40. include/libc.h +3 −0
  41. include/libsec.h +340 −0
  42. include/memdraw.h +200 −0
  43. include/memlayer.h +51 −0
  44. include/mp.h +134 −0
  45. include/u.h +26 −0
  46. include/unix.h +14 −0
  47. include/user.h +65 −0
  48. include/x +0 −0
  49. include/x.c +6 −0
  50. kern/Makefile +50 −0
  51. kern/allocb.c +165 −0
  52. kern/cache.c +46 −0
  53. kern/chan.c +1496 −0
  54. kern/dat.h +519 −0
  55. kern/data.c +31 −0
  56. kern/dev.c +468 −0
  57. kern/devcons.c +1238 −0
  58. kern/devdraw.c +2100 −0
  59. kern/devfs.c +638 −0
  60. kern/devip-posix.c +209 −0
  61. kern/devip-win.c +208 −0
  62. kern/devip.c +936 −0
  63. kern/devip.h +17 −0
  64. kern/devmnt.c +1214 −0
  65. kern/devmouse.c +237 −0
  66. kern/devntfs.c +704 −0
  67. kern/devpipe.c +398 −0
  68. kern/devroot.c +268 −0
  69. kern/devssl.c +1512 −0
  70. kern/devtab.c +27 −0
  71. kern/error.c +50 −0
  72. kern/error.h +50 −0
  73. kern/exportfs.c +821 −0
  74. kern/fns.h +377 −0
  75. kern/mkfile +47 −0
  76. kern/netif.h +133 −0
  77. kern/os-windows.c +184 −0
  78. kern/parse.c +113 −0
  79. kern/pgrp.c +272 −0
  80. kern/posix.c +190 −0
  81. kern/procinit.c +67 −0
  82. kern/qio.c +1524 −0
  83. kern/qlock.c +94 −0
  84. kern/rendez.c +90 −0
  85. kern/rwlock.c +39 −0
  86. kern/screen.h +59 −0
  87. kern/sleep.c +90 −0
  88. kern/smalloc.c +18 −0
  89. kern/stub.c +170 −0
  90. kern/syscall.c +837 −0
  91. kern/sysfile.c +1242 −0
  92. kern/sysproc.c +32 −0
  93. kern/term.c +204 −0
  94. kern/todo.c +0 −0
  95. kern/uart.c +14 −0
  96. kern/waserror.c +27 −0
  97. kern/winduhz.h +18 −0
  98. kern/x +601 −0
  99. latin1.c +177 −0
  100. libauthsrv/Makefile +28 −0
  101. libauthsrv/authdial.c +31 −0
  102. libauthsrv/convA2M.c +25 −0
  103. libauthsrv/convM2A.c +23 −0
  104. libauthsrv/convM2PR.c +28 −0
  105. libauthsrv/convM2T.c +28 −0
  106. libauthsrv/convM2TR.c +28 −0
  107. libauthsrv/convPR2M.c +28 −0
  108. libauthsrv/convT2M.c +27 −0
  109. libauthsrv/convTR2M.c +27 −0
  110. libauthsrv/mkfile +25 −0
  111. libauthsrv/nvcsum.c +16 −0
  112. libauthsrv/opasstokey.c +29 −0
  113. libauthsrv/passtokey.c +33 −0
  114. libauthsrv/readnvram.c +368 −0
  115. libc/Makefile +89 −0
  116. libc/charstod.c +81 −0
  117. libc/cleanname.c +52 −0
  118. libc/convD2M.c +95 −0
  119. libc/convM2D.c +94 −0
  120. libc/convM2S.c +315 −0
  121. libc/convS2M.c +386 −0
  122. libc/crypt.c +68 −0
  123. libc/dial.c +209 −0
  124. libc/dirfstat.c +37 −0
  125. libc/dirfwstat.c +19 −0
  126. libc/dirmodefmt.c +48 −0
  127. libc/dirstat.c +37 −0
  128. libc/dirwstat.c +19 −0
  129. libc/dofmt.c +520 −0
  130. libc/dorfmt.c +46 −0
  131. libc/errfmt.c +12 −0
  132. libc/fcallfmt.c +234 −0
  133. libc/fltfmt.c +312 −0
  134. libc/fmt.c +193 −0
  135. libc/fmt.h +99 −0
  136. libc/fmtdef.h +85 −0
  137. libc/fmtfd.c +31 −0
  138. libc/fmtlock.c +16 −0
  139. libc/fmtprint.c +32 −0
  140. libc/fmtquote.c +247 −0
  141. libc/fmtrune.c +25 −0
  142. libc/fmtstr.c +11 −0
  143. libc/fmtvprint.c +31 −0
  144. libc/fprint.c +14 −0
  145. libc/frand.c +17 −0
  146. libc/getfields.c +37 −0
  147. libc/getpid.c +17 −0
  148. libc/lnrand.c +18 −0
  149. libc/lock.c +64 −0
  150. libc/lrand.c +83 −0
  151. libc/mallocz.c +13 −0
  152. libc/mkfile +90 −0
  153. libc/nan.h +4 −0
  154. libc/nan64.c +55 −0
  155. libc/netmkaddr.c +52 −0
  156. libc/nrand.c +18 −0
  157. libc/nsec.c +66 −0
  158. libc/pow10.c +49 −0
  159. libc/print.c +14 −0
  160. libc/pushssl.c +44 −0
  161. libc/rand.c +8 −0
  162. libc/read9pmsg.c +31 −0
  163. libc/readn.c +22 −0
  164. libc/rune.c +162 −0
  165. libc/runefmtstr.c +11 −0
  166. libc/runeseprint.c +14 −0
  167. libc/runesmprint.c +14 −0
  168. libc/runesnprint.c +15 −0
  169. libc/runesprint.c +14 −0
  170. libc/runestrcat.c +10 −0
  171. libc/runestrchr.c +20 −0
  172. libc/runestrcmp.c +20 −0
  173. libc/runestrcpy.c +13 −0
  174. libc/runestrdup.c +14 −0
  175. libc/runestrecpy.c +17 −0
  176. libc/runestrlen.c +9 −0
  177. libc/runestrncat.c +17 −0
  178. libc/runestrncmp.c +22 −0
  179. libc/runestrncpy.c +18 −0
  180. libc/runestrrchr.c +15 −0
  181. libc/runestrstr.c +29 −0
  182. libc/runetype.c +1138 −0
  183. libc/runevseprint.c +23 −0
  184. libc/runevsmprint.c +70 −0
  185. libc/runevsnprint.c +22 −0
  186. libc/seprint.c +14 −0
  187. libc/smprint.c +14 −0
  188. libc/snprint.c +15 −0
  189. libc/sprint.c +14 −0
  190. libc/strecpy.c +17 −0
  191. libc/strtod.c +532 −0
  192. libc/strtod.h +4 −0
  193. libc/strtoll.c +93 −0
  194. libc/sysfatal.c +30 −0
  195. libc/time.c +51 −0
  196. libc/tokenize.c +107 −0
  197. libc/truerand.c +17 −0
  198. libc/u16.c +53 −0
  199. libc/u32.c +110 −0
  200. libc/u64.c +127 −0
  201. libc/utf.h +51 −0
  202. libc/utfdef.h +14 −0
  203. libc/utfecpy.c +21 −0
  204. libc/utflen.c +23 −0
  205. libc/utfnlen.c +26 −0
  206. libc/utfrrune.c +31 −0
  207. libc/utfrune.c +30 −0
  208. libc/utfutf.c +26 −0
  209. libc/vfprint.c +34 −0
  210. libc/vseprint.c +23 −0
  211. libc/vsmprint.c +70 −0
  212. libc/vsnprint.c +22 −0
  213. libdraw/Makefile +24 −0
  214. libdraw/alloc.c +237 −0
  215. libdraw/arith.c +206 −0
  216. libdraw/bytesperline.c +34 −0
  217. libdraw/chan.c +77 −0
  218. libdraw/defont.c +402 −0
  219. libdraw/drawrepl.c +23 −0
  220. libdraw/icossin.c +140 −0
  221. libdraw/icossin2.c +261 −0
  222. libdraw/mkfile +18 −0
  223. libdraw/rectclip.c +25 −0
  224. libdraw/rgb.c +99 −0
  225. libmemdraw/Makefile +33 −0
  226. libmemdraw/alloc.c +200 −0
  227. libmemdraw/alpha.hoc +9 −0
  228. libmemdraw/arc.c +117 −0
  229. libmemdraw/arctest.c +62 −0
  230. libmemdraw/cload.c +68 −0
  231. libmemdraw/cmap.c +320 −0
  232. libmemdraw/cread.c +96 −0
  233. libmemdraw/defont.c +68 −0
  234. libmemdraw/draw.c +2499 −0
  235. libmemdraw/drawtest.c +1004 −0
  236. libmemdraw/ellipse.c +248 −0
  237. libmemdraw/fillpoly.c +523 −0
  238. libmemdraw/hwdraw.c +12 −0
  239. libmemdraw/iprint.c +12 −0
  240. libmemdraw/line.c +485 −0
  241. libmemdraw/load.c +72 −0
  242. libmemdraw/mkcmap.c +79 −0
  243. libmemdraw/mkfile +27 −0
  244. libmemdraw/openmemsubfont.c +53 −0
  245. libmemdraw/poly.c +24 −0
  246. libmemdraw/read.c +111 −0
  247. libmemdraw/string.c +68 −0
  248. libmemdraw/subfont.c +34 −0
  249. libmemdraw/times +19 −0
  250. libmemdraw/unload.c +25 −0
  251. libmemdraw/write.c +183 −0
  252. libmemlayer/Makefile +26 −0
  253. libmemlayer/draw.c +192 −0
  254. libmemlayer/lalloc.c +79 −0
  255. libmemlayer/layerop.c +112 −0
  256. libmemlayer/ldelete.c +67 −0
  257. libmemlayer/lhide.c +67 −0
  258. libmemlayer/line.c +122 −0
  259. libmemlayer/load.c +55 −0
  260. libmemlayer/lorigin.c +107 −0
  261. libmemlayer/lsetrefresh.c +35 −0
  262. libmemlayer/ltofront.c +80 −0
  263. libmemlayer/ltorear.c +69 −0
  264. libmemlayer/mkfile +23 −0
  265. libmemlayer/unload.c +52 −0
  266. libmp/Makefile +46 −0
  267. libmp/betomp.c +40 −0
  268. libmp/crt.c +122 −0
  269. libmp/crttest.c +54 −0
  270. libmp/dat.h +15 −0
  271. libmp/letomp.c +29 −0
  272. libmp/mkfile +40 −0
  273. libmp/mpadd.c +54 −0
  274. libmp/mpaux.c +185 −0
  275. libmp/mpcmp.c +28 −0
  276. libmp/mpdigdiv.c +43 −0
  277. libmp/mpdiv.c +112 −0
  278. libmp/mpeuclid.c +82 −0
  279. libmp/mpexp.c +86 −0
  280. libmp/mpextendedgcd.c +97 −0
  281. libmp/mpfmt.c +193 −0
  282. libmp/mpinvert.c +21 −0
  283. libmp/mpleft.c +46 −0
  284. libmp/mpmod.c +15 −0
  285. libmp/mpmul.c +156 −0
  286. libmp/mprand.c +42 −0
  287. libmp/mpright.c +40 −0
  288. libmp/mpsub.c +52 −0
  289. libmp/mptobe.c +57 −0
  290. libmp/mptoi.c +44 −0
  291. libmp/mptole.c +54 −0
  292. libmp/mptoui.c +35 −0
  293. libmp/mptouv.c +49 −0
  294. libmp/mptov.c +69 −0
  295. libmp/mpvecadd.c +35 −0
  296. libmp/mpveccmp.c +28 −0
  297. libmp/mpvecdigmuladd.c +103 −0
  298. libmp/mpvecsub.c +34 −0
  299. libmp/os.h +3 −0
  300. libmp/reduce +16 −0
  301. libmp/strtomp.c +205 −0
  302. libsec/Makefile +60 −0
  303. libsec/aes.c +1544 −0
  304. libsec/blowfish.c +579 −0
  305. libsec/decodepem.c +59 −0
  306. libsec/des.c +480 −0
  307. libsec/des3CBC.c +59 −0
  308. libsec/des3ECB.c +48 −0
  309. libsec/desCBC.c +59 −0
  310. libsec/desECB.c +48 −0
  311. libsec/desmodes.c +31 −0
  312. libsec/dsaalloc.c +69 −0
  313. libsec/dsagen.c +61 −0
  314. libsec/dsaprimes.c +97 −0
  315. libsec/dsaprivtopub.c +16 −0
  316. libsec/dsasign.c +52 −0
  317. libsec/dsaverify.c +46 −0
  318. libsec/egalloc.c +67 −0
  319. libsec/egdecrypt.c +28 −0
  320. libsec/egencrypt.c +38 −0
  321. libsec/eggen.c +21 −0
  322. libsec/egprivtopub.c +17 −0
  323. libsec/egsign.c +43 −0
  324. libsec/egtest.c +34 −0
  325. libsec/egverify.c +29 −0
  326. libsec/fastrand.c +16 −0
  327. libsec/genprime.c +27 −0
  328. libsec/genrandom.c +62 −0
  329. libsec/gensafeprime.c +36 −0
  330. libsec/genstrongprime.c +57 −0
  331. libsec/hmac.c +56 −0
  332. libsec/hmactest.c +19 −0
  333. libsec/md4.c +271 −0
  334. libsec/md4test.c +31 −0
  335. libsec/md5.c +148 −0
  336. libsec/md5block.c +267 −0
  337. libsec/md5pickle.c +37 −0
  338. libsec/mkfile +55 −0
  339. libsec/nfastrand.c +23 −0
  340. libsec/os.h +2 −0
  341. libsec/primetest.c +41 −0
  342. libsec/prng.c +15 −0
  343. libsec/probably_prime.c +84 −0
  344. libsec/ranlib.core +0 −0
  345. libsec/rc4.c +104 −0
  346. libsec/readcert.c +50 −0
  347. libsec/rsaalloc.c +52 −0
  348. libsec/rsadecrypt.c +37 −0
  349. libsec/rsaencrypt.c +12 −0
  350. libsec/rsafill.c +61 −0
  351. libsec/rsagen.c +82 −0
  352. libsec/rsaprivtopub.c +16 −0
  353. libsec/rsatest.c +57 −0
  354. libsec/sha1.c +127 −0
  355. libsec/sha1block.c +187 −0
  356. libsec/sha1pickle.c +38 −0
  357. libsec/smallprimes.c +1004 −0
  358. libsec/smallprimetest.c +1039 −0
  359. libsec/thumb.c +97 −0
  360. libsec/tlshand.c +2291 −0
  361. libsec/x509.c +2520 −0
  362. main.c +126 −0
  363. mkfile +95 −0
  364. mkfile-Windows +54 −0
  365. mkfile-posix +9 −0
  366. mkone +50 −0
  367. posix-386/Makefile +16 −0
  368. posix-386/getcallerpc.c +8 −0
  369. posix-386/md5block.s +241 −0
  370. posix-386/sha1block.s +214 −0
  371. posix-386/tas.c +23 −0
  372. posix-power/Makefile +16 −0
  373. posix-power/getcallerpc.c +8 −0
  374. posix-power/tas.c +42 −0
  375. readcons.c +110 −0
  376. resource.h +16 −0
  377. secstore.c +667 −0
  378. win32-386/getcallerpc.c +8 −0
  379. win32-386/md5block.s +241 −0
  380. win32-386/mkfile +10 −0
  381. win32-386/sha1block.s +214 −0
  382. win32-386/tas.c +22 −0
Makefile+82−0
@@ -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+
Notes+16−0
@@ -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+
args.h+20−0
@@ -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)))
cpu.c+606−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+
drawterm.h+10−0
@@ -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*);
drawterm.ico+0−0

Binary file not shown.

drawterm.rc+72−0
@@ -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+
drawterm.res+0−0

Binary file not shown.

exportfs/Makefile+16−0
@@ -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+
exportfs/exportfs.c+503−0
@@ -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+
exportfs/exportfs.h+148−0
@@ -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
exportfs/exportsrv.c+679−0
@@ -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+}
exportfs/mkfile+11−0
@@ -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
gui-win32/alloc.c+23−0
@@ -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+
gui-win32/cload.c+10−0
@@ -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+}
gui-win32/draw.c+22−0
@@ -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+}
gui-win32/load.c+10−0
@@ -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+}
gui-win32/mkfile+14−0
@@ -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
gui-win32/screen.c+642−0
@@ -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+}
gui-win32/wstrtoutf.c+35−0
@@ -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+}
gui-x11/Makefile+20−0
@@ -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+
gui-x11/alloc.c+209−0
@@ -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+}
gui-x11/cload.c+16−0
@@ -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+}
gui-x11/draw.c+189−0
@@ -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+}
gui-x11/keysym2ucs-x11.c+857−0
@@ -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+}
gui-x11/keysym2ucs.h+9−0
@@ -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);
gui-x11/ksym2utf.h+754−0
@@ -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+};
gui-x11/load.c+16−0
@@ -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+}
gui-x11/screen.c+1094−0
@@ -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+}
gui-x11/xmem.h+60−0
@@ -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);
include/a.out+0−0

Binary file not shown.

include/auth.h+144−0
@@ -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
include/authsrv.h+166−0
@@ -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**);
include/cursor.h+6−0
@@ -0,0 +1,6 @@
1+struct Cursor
2+{
3+ Point offset;
4+ uchar clr[2*16];
5+ uchar set[2*16];
6+};
include/draw.h+519−0
@@ -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);
include/dtos.h+10−0
@@ -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
include/fcall.h+110−0
@@ -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+
include/keyboard.h+42−0
@@ -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+
include/lib.h+246−0
@@ -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);
include/libc.h+3−0
@@ -0,0 +1,3 @@
1+#include "lib.h"
2+#include "user.h"
3+
include/libsec.h+340−0
@@ -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);
include/memdraw.h+200−0
@@ -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+
include/memlayer.h+51−0
@@ -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*);
include/mp.h+134−0
@@ -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+
include/u.h+26−0
@@ -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
include/unix.h+14−0
@@ -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;
include/user.h+65−0
@@ -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;
include/x+0−0

Empty file added.

include/x.c+6−0
@@ -0,0 +1,6 @@
1+#include <stdio.h>
2+
3+void
4+main(void)
5+{
6+}
kern/Makefile+50−0
@@ -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+
kern/allocb.c+165−0
@@ -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+}
kern/cache.c+46−0
@@ -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+}
kern/chan.c+1496−0
@@ -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+}
kern/dat.h+519−0
@@ -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())
kern/data.c+31−0
@@ -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";
kern/dev.c+468−0
@@ -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+}
kern/devcons.c+1238−0
@@ -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*)&order;
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*)&order;
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+
kern/devdraw.c+2100−0
@@ -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+
kern/devfs.c+638−0
@@ -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+};
kern/devip-posix.c+209−0
@@ -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+}
kern/devip-win.c+208−0
@@ -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+}
kern/devip.c+936−0
@@ -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+
kern/devip.h+17−0
@@ -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+
kern/devmnt.c+1214−0
@@ -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+};
kern/devmouse.c+237−0
@@ -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+
kern/devntfs.c+704−0
@@ -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+};
kern/devpipe.c+398−0
@@ -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+};
kern/devroot.c+268−0
@@ -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+
kern/devssl.c+1512−0
@@ -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.

kern/devtab.c+27−0

This diff is large: its 28 lines aren’t shown here.

kern/error.c+50−0

This diff is large: its 51 lines aren’t shown here.

kern/error.h+50−0

This diff is large: its 51 lines aren’t shown here.

kern/exportfs.c+821−0

This diff is large: its 822 lines aren’t shown here.

kern/fns.h+377−0

This diff is large: its 378 lines aren’t shown here.

kern/mkfile+47−0

This diff is large: its 48 lines aren’t shown here.

kern/netif.h+133−0

This diff is large: its 134 lines aren’t shown here.

kern/os-windows.c+184−0

This diff is large: its 185 lines aren’t shown here.

kern/parse.c+113−0

This diff is large: its 114 lines aren’t shown here.

kern/pgrp.c+272−0

This diff is large: its 273 lines aren’t shown here.

kern/posix.c+190−0

This diff is large: its 191 lines aren’t shown here.

kern/procinit.c+67−0

This diff is large: its 68 lines aren’t shown here.

kern/qio.c+1524−0

This diff is large: its 1525 lines aren’t shown here.

kern/qlock.c+94−0

This diff is large: its 95 lines aren’t shown here.

kern/rendez.c+90−0

This diff is large: its 91 lines aren’t shown here.

kern/rwlock.c+39−0

This diff is large: its 40 lines aren’t shown here.

kern/screen.h+59−0

This diff is large: its 60 lines aren’t shown here.

kern/sleep.c+90−0

This diff is large: its 91 lines aren’t shown here.

kern/smalloc.c+18−0

This diff is large: its 19 lines aren’t shown here.

kern/stub.c+170−0

This diff is large: its 171 lines aren’t shown here.

kern/syscall.c+837−0

This diff is large: its 838 lines aren’t shown here.

kern/sysfile.c+1242−0

This diff is large: its 1243 lines aren’t shown here.

kern/sysproc.c+32−0

This diff is large: its 33 lines aren’t shown here.

kern/term.c+204−0

This diff is large: its 205 lines aren’t shown here.

kern/todo.c+0−0

Empty file added.

kern/uart.c+14−0

This diff is large: its 15 lines aren’t shown here.

kern/waserror.c+27−0

This diff is large: its 28 lines aren’t shown here.

kern/winduhz.h+18−0

This diff is large: its 19 lines aren’t shown here.

kern/x+601−0

This diff is large: its 602 lines aren’t shown here.

latin1.c+177−0

This diff is large: its 178 lines aren’t shown here.

libauthsrv/Makefile+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/authdial.c+31−0

This diff is large: its 32 lines aren’t shown here.

libauthsrv/convA2M.c+25−0

This diff is large: its 26 lines aren’t shown here.

libauthsrv/convM2A.c+23−0

This diff is large: its 24 lines aren’t shown here.

libauthsrv/convM2PR.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convM2T.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convM2TR.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convPR2M.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convT2M.c+27−0

This diff is large: its 28 lines aren’t shown here.

libauthsrv/convTR2M.c+27−0

This diff is large: its 28 lines aren’t shown here.

libauthsrv/mkfile+25−0

This diff is large: its 26 lines aren’t shown here.

libauthsrv/nvcsum.c+16−0

This diff is large: its 17 lines aren’t shown here.

libauthsrv/opasstokey.c+29−0

This diff is large: its 30 lines aren’t shown here.

libauthsrv/passtokey.c+33−0

This diff is large: its 34 lines aren’t shown here.

libauthsrv/readnvram.c+368−0

This diff is large: its 369 lines aren’t shown here.

libc/Makefile+89−0

This diff is large: its 90 lines aren’t shown here.

libc/charstod.c+81−0

This diff is large: its 82 lines aren’t shown here.

libc/cleanname.c+52−0

This diff is large: its 53 lines aren’t shown here.

libc/convD2M.c+95−0

This diff is large: its 96 lines aren’t shown here.

libc/convM2D.c+94−0

This diff is large: its 95 lines aren’t shown here.

libc/convM2S.c+315−0

This diff is large: its 316 lines aren’t shown here.

libc/convS2M.c+386−0

This diff is large: its 387 lines aren’t shown here.

libc/crypt.c+68−0

This diff is large: its 69 lines aren’t shown here.

libc/dial.c+209−0

This diff is large: its 210 lines aren’t shown here.

libc/dirfstat.c+37−0

This diff is large: its 38 lines aren’t shown here.

libc/dirfwstat.c+19−0

This diff is large: its 20 lines aren’t shown here.

libc/dirmodefmt.c+48−0

This diff is large: its 49 lines aren’t shown here.

libc/dirstat.c+37−0

This diff is large: its 38 lines aren’t shown here.

libc/dirwstat.c+19−0

This diff is large: its 20 lines aren’t shown here.

libc/dofmt.c+520−0

This diff is large: its 521 lines aren’t shown here.

libc/dorfmt.c+46−0

This diff is large: its 47 lines aren’t shown here.

libc/errfmt.c+12−0

This diff is large: its 13 lines aren’t shown here.

libc/fcallfmt.c+234−0

This diff is large: its 235 lines aren’t shown here.

libc/fltfmt.c+312−0

This diff is large: its 313 lines aren’t shown here.

libc/fmt.c+193−0

This diff is large: its 194 lines aren’t shown here.

libc/fmt.h+99−0

This diff is large: its 100 lines aren’t shown here.

libc/fmtdef.h+85−0

This diff is large: its 86 lines aren’t shown here.

libc/fmtfd.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/fmtlock.c+16−0

This diff is large: its 17 lines aren’t shown here.

libc/fmtprint.c+32−0

This diff is large: its 33 lines aren’t shown here.

libc/fmtquote.c+247−0

This diff is large: its 248 lines aren’t shown here.

libc/fmtrune.c+25−0

This diff is large: its 26 lines aren’t shown here.

libc/fmtstr.c+11−0

This diff is large: its 12 lines aren’t shown here.

libc/fmtvprint.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/fprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/frand.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/getfields.c+37−0

This diff is large: its 38 lines aren’t shown here.

libc/getpid.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/lnrand.c+18−0

This diff is large: its 19 lines aren’t shown here.

libc/lock.c+64−0

This diff is large: its 65 lines aren’t shown here.

libc/lrand.c+83−0

This diff is large: its 84 lines aren’t shown here.

libc/mallocz.c+13−0

This diff is large: its 14 lines aren’t shown here.

libc/mkfile+90−0

This diff is large: its 91 lines aren’t shown here.

libc/nan.h+4−0

This diff is large: its 5 lines aren’t shown here.

libc/nan64.c+55−0

This diff is large: its 56 lines aren’t shown here.

libc/netmkaddr.c+52−0

This diff is large: its 53 lines aren’t shown here.

libc/nrand.c+18−0

This diff is large: its 19 lines aren’t shown here.

libc/nsec.c+66−0

This diff is large: its 67 lines aren’t shown here.

libc/pow10.c+49−0

This diff is large: its 50 lines aren’t shown here.

libc/print.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/pushssl.c+44−0

This diff is large: its 45 lines aren’t shown here.

libc/rand.c+8−0

This diff is large: its 9 lines aren’t shown here.

libc/read9pmsg.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/readn.c+22−0

This diff is large: its 23 lines aren’t shown here.

libc/rune.c+162−0

This diff is large: its 163 lines aren’t shown here.

libc/runefmtstr.c+11−0

This diff is large: its 12 lines aren’t shown here.

libc/runeseprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runesmprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runesnprint.c+15−0

This diff is large: its 16 lines aren’t shown here.

libc/runesprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runestrcat.c+10−0

This diff is large: its 11 lines aren’t shown here.

libc/runestrchr.c+20−0

This diff is large: its 21 lines aren’t shown here.

libc/runestrcmp.c+20−0

This diff is large: its 21 lines aren’t shown here.

libc/runestrcpy.c+13−0

This diff is large: its 14 lines aren’t shown here.

libc/runestrdup.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runestrecpy.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/runestrlen.c+9−0

This diff is large: its 10 lines aren’t shown here.

libc/runestrncat.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/runestrncmp.c+22−0

This diff is large: its 23 lines aren’t shown here.

libc/runestrncpy.c+18−0

This diff is large: its 19 lines aren’t shown here.

libc/runestrrchr.c+15−0

This diff is large: its 16 lines aren’t shown here.

libc/runestrstr.c+29−0

This diff is large: its 30 lines aren’t shown here.

libc/runetype.c+1138−0

This diff is large: its 1139 lines aren’t shown here.

libc/runevseprint.c+23−0

This diff is large: its 24 lines aren’t shown here.

libc/runevsmprint.c+70−0

This diff is large: its 71 lines aren’t shown here.

libc/runevsnprint.c+22−0

This diff is large: its 23 lines aren’t shown here.

libc/seprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/smprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/snprint.c+15−0

This diff is large: its 16 lines aren’t shown here.

libc/sprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/strecpy.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/strtod.c+532−0

This diff is large: its 533 lines aren’t shown here.

libc/strtod.h+4−0

This diff is large: its 5 lines aren’t shown here.

libc/strtoll.c+93−0

This diff is large: its 94 lines aren’t shown here.

libc/sysfatal.c+30−0

This diff is large: its 31 lines aren’t shown here.

libc/time.c+51−0

This diff is large: its 52 lines aren’t shown here.

libc/tokenize.c+107−0

This diff is large: its 108 lines aren’t shown here.

libc/truerand.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/u16.c+53−0

This diff is large: its 54 lines aren’t shown here.

libc/u32.c+110−0

This diff is large: its 111 lines aren’t shown here.

libc/u64.c+127−0

This diff is large: its 128 lines aren’t shown here.

libc/utf.h+51−0

This diff is large: its 52 lines aren’t shown here.

libc/utfdef.h+14−0

This diff is large: its 15 lines aren’t shown here.

libc/utfecpy.c+21−0

This diff is large: its 22 lines aren’t shown here.

libc/utflen.c+23−0

This diff is large: its 24 lines aren’t shown here.

libc/utfnlen.c+26−0

This diff is large: its 27 lines aren’t shown here.

libc/utfrrune.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/utfrune.c+30−0

This diff is large: its 31 lines aren’t shown here.

libc/utfutf.c+26−0

This diff is large: its 27 lines aren’t shown here.

libc/vfprint.c+34−0

This diff is large: its 35 lines aren’t shown here.

libc/vseprint.c+23−0

This diff is large: its 24 lines aren’t shown here.

libc/vsmprint.c+70−0

This diff is large: its 71 lines aren’t shown here.

libc/vsnprint.c+22−0

This diff is large: its 23 lines aren’t shown here.

libdraw/Makefile+24−0

This diff is large: its 25 lines aren’t shown here.

libdraw/alloc.c+237−0

This diff is large: its 238 lines aren’t shown here.

libdraw/arith.c+206−0

This diff is large: its 207 lines aren’t shown here.

libdraw/bytesperline.c+34−0

This diff is large: its 35 lines aren’t shown here.

libdraw/chan.c+77−0

This diff is large: its 78 lines aren’t shown here.

libdraw/defont.c+402−0

This diff is large: its 403 lines aren’t shown here.

libdraw/drawrepl.c+23−0

This diff is large: its 24 lines aren’t shown here.

libdraw/icossin.c+140−0

This diff is large: its 141 lines aren’t shown here.

libdraw/icossin2.c+261−0

This diff is large: its 262 lines aren’t shown here.

libdraw/mkfile+18−0

This diff is large: its 19 lines aren’t shown here.

libdraw/rectclip.c+25−0

This diff is large: its 26 lines aren’t shown here.

libdraw/rgb.c+99−0

This diff is large: its 100 lines aren’t shown here.

libmemdraw/Makefile+33−0

This diff is large: its 34 lines aren’t shown here.

libmemdraw/alloc.c+200−0

This diff is large: its 201 lines aren’t shown here.

libmemdraw/alpha.hoc+9−0

This diff is large: its 10 lines aren’t shown here.

libmemdraw/arc.c+117−0

This diff is large: its 118 lines aren’t shown here.

libmemdraw/arctest.c+62−0

This diff is large: its 63 lines aren’t shown here.

libmemdraw/cload.c+68−0

This diff is large: its 69 lines aren’t shown here.

libmemdraw/cmap.c+320−0

This diff is large: its 321 lines aren’t shown here.

libmemdraw/cread.c+96−0

This diff is large: its 97 lines aren’t shown here.

libmemdraw/defont.c+68−0

This diff is large: its 69 lines aren’t shown here.

libmemdraw/draw.c+2499−0

This diff is large: its 2500 lines aren’t shown here.

libmemdraw/drawtest.c+1004−0

This diff is large: its 1005 lines aren’t shown here.

libmemdraw/ellipse.c+248−0

This diff is large: its 249 lines aren’t shown here.

libmemdraw/fillpoly.c+523−0

This diff is large: its 524 lines aren’t shown here.

libmemdraw/hwdraw.c+12−0

This diff is large: its 13 lines aren’t shown here.

libmemdraw/iprint.c+12−0

This diff is large: its 13 lines aren’t shown here.

libmemdraw/line.c+485−0

This diff is large: its 486 lines aren’t shown here.

libmemdraw/load.c+72−0

This diff is large: its 73 lines aren’t shown here.

libmemdraw/mkcmap.c+79−0

This diff is large: its 80 lines aren’t shown here.

libmemdraw/mkfile+27−0

This diff is large: its 28 lines aren’t shown here.

libmemdraw/openmemsubfont.c+53−0

This diff is large: its 54 lines aren’t shown here.

libmemdraw/poly.c+24−0

This diff is large: its 25 lines aren’t shown here.

libmemdraw/read.c+111−0

This diff is large: its 112 lines aren’t shown here.

libmemdraw/string.c+68−0

This diff is large: its 69 lines aren’t shown here.

libmemdraw/subfont.c+34−0

This diff is large: its 35 lines aren’t shown here.

libmemdraw/times+19−0

This diff is large: its 20 lines aren’t shown here.

libmemdraw/unload.c+25−0

This diff is large: its 26 lines aren’t shown here.

libmemdraw/write.c+183−0

This diff is large: its 184 lines aren’t shown here.

libmemlayer/Makefile+26−0

This diff is large: its 27 lines aren’t shown here.

libmemlayer/draw.c+192−0

This diff is large: its 193 lines aren’t shown here.

libmemlayer/lalloc.c+79−0

This diff is large: its 80 lines aren’t shown here.

libmemlayer/layerop.c+112−0

This diff is large: its 113 lines aren’t shown here.

libmemlayer/ldelete.c+67−0

This diff is large: its 68 lines aren’t shown here.

libmemlayer/lhide.c+67−0

This diff is large: its 68 lines aren’t shown here.

libmemlayer/line.c+122−0

This diff is large: its 123 lines aren’t shown here.

libmemlayer/load.c+55−0

This diff is large: its 56 lines aren’t shown here.

libmemlayer/lorigin.c+107−0

This diff is large: its 108 lines aren’t shown here.

libmemlayer/lsetrefresh.c+35−0

This diff is large: its 36 lines aren’t shown here.

libmemlayer/ltofront.c+80−0

This diff is large: its 81 lines aren’t shown here.

libmemlayer/ltorear.c+69−0

This diff is large: its 70 lines aren’t shown here.

libmemlayer/mkfile+23−0

This diff is large: its 24 lines aren’t shown here.

libmemlayer/unload.c+52−0

This diff is large: its 53 lines aren’t shown here.

libmp/Makefile+46−0

This diff is large: its 47 lines aren’t shown here.

libmp/betomp.c+40−0

This diff is large: its 41 lines aren’t shown here.

libmp/crt.c+122−0

This diff is large: its 123 lines aren’t shown here.

libmp/crttest.c+54−0

This diff is large: its 55 lines aren’t shown here.

libmp/dat.h+15−0

This diff is large: its 16 lines aren’t shown here.

libmp/letomp.c+29−0

This diff is large: its 30 lines aren’t shown here.

libmp/mkfile+40−0

This diff is large: its 41 lines aren’t shown here.

libmp/mpadd.c+54−0

This diff is large: its 55 lines aren’t shown here.

libmp/mpaux.c+185−0

This diff is large: its 186 lines aren’t shown here.

libmp/mpcmp.c+28−0

This diff is large: its 29 lines aren’t shown here.

libmp/mpdigdiv.c+43−0

This diff is large: its 44 lines aren’t shown here.

libmp/mpdiv.c+112−0

This diff is large: its 113 lines aren’t shown here.

libmp/mpeuclid.c+82−0

This diff is large: its 83 lines aren’t shown here.

libmp/mpexp.c+86−0

This diff is large: its 87 lines aren’t shown here.

libmp/mpextendedgcd.c+97−0

This diff is large: its 98 lines aren’t shown here.

libmp/mpfmt.c+193−0

This diff is large: its 194 lines aren’t shown here.

libmp/mpinvert.c+21−0

This diff is large: its 22 lines aren’t shown here.

libmp/mpleft.c+46−0

This diff is large: its 47 lines aren’t shown here.

libmp/mpmod.c+15−0

This diff is large: its 16 lines aren’t shown here.

libmp/mpmul.c+156−0

This diff is large: its 157 lines aren’t shown here.

libmp/mprand.c+42−0

This diff is large: its 43 lines aren’t shown here.

libmp/mpright.c+40−0

This diff is large: its 41 lines aren’t shown here.

libmp/mpsub.c+52−0

This diff is large: its 53 lines aren’t shown here.

libmp/mptobe.c+57−0

This diff is large: its 58 lines aren’t shown here.

libmp/mptoi.c+44−0

This diff is large: its 45 lines aren’t shown here.

libmp/mptole.c+54−0

This diff is large: its 55 lines aren’t shown here.

libmp/mptoui.c+35−0

This diff is large: its 36 lines aren’t shown here.

libmp/mptouv.c+49−0

This diff is large: its 50 lines aren’t shown here.

libmp/mptov.c+69−0

This diff is large: its 70 lines aren’t shown here.

libmp/mpvecadd.c+35−0

This diff is large: its 36 lines aren’t shown here.

libmp/mpveccmp.c+28−0

This diff is large: its 29 lines aren’t shown here.

libmp/mpvecdigmuladd.c+103−0

This diff is large: its 104 lines aren’t shown here.

libmp/mpvecsub.c+34−0

This diff is large: its 35 lines aren’t shown here.

libmp/os.h+3−0

This diff is large: its 4 lines aren’t shown here.

libmp/reduce+16−0

This diff is large: its 17 lines aren’t shown here.

libmp/strtomp.c+205−0

This diff is large: its 206 lines aren’t shown here.

libsec/Makefile+60−0

This diff is large: its 61 lines aren’t shown here.

libsec/aes.c+1544−0

This diff is large: its 1545 lines aren’t shown here.

libsec/blowfish.c+579−0

This diff is large: its 580 lines aren’t shown here.

libsec/decodepem.c+59−0

This diff is large: its 60 lines aren’t shown here.

libsec/des.c+480−0

This diff is large: its 481 lines aren’t shown here.

libsec/des3CBC.c+59−0

This diff is large: its 60 lines aren’t shown here.

libsec/des3ECB.c+48−0

This diff is large: its 49 lines aren’t shown here.

libsec/desCBC.c+59−0

This diff is large: its 60 lines aren’t shown here.

libsec/desECB.c+48−0

This diff is large: its 49 lines aren’t shown here.

libsec/desmodes.c+31−0

This diff is large: its 32 lines aren’t shown here.

libsec/dsaalloc.c+69−0

This diff is large: its 70 lines aren’t shown here.

libsec/dsagen.c+61−0

This diff is large: its 62 lines aren’t shown here.

libsec/dsaprimes.c+97−0

This diff is large: its 98 lines aren’t shown here.

libsec/dsaprivtopub.c+16−0

This diff is large: its 17 lines aren’t shown here.

libsec/dsasign.c+52−0

This diff is large: its 53 lines aren’t shown here.

libsec/dsaverify.c+46−0

This diff is large: its 47 lines aren’t shown here.

libsec/egalloc.c+67−0

This diff is large: its 68 lines aren’t shown here.

libsec/egdecrypt.c+28−0

This diff is large: its 29 lines aren’t shown here.

libsec/egencrypt.c+38−0

This diff is large: its 39 lines aren’t shown here.

libsec/eggen.c+21−0

This diff is large: its 22 lines aren’t shown here.

libsec/egprivtopub.c+17−0

This diff is large: its 18 lines aren’t shown here.

libsec/egsign.c+43−0

This diff is large: its 44 lines aren’t shown here.

libsec/egtest.c+34−0

This diff is large: its 35 lines aren’t shown here.

libsec/egverify.c+29−0

This diff is large: its 30 lines aren’t shown here.

libsec/fastrand.c+16−0

This diff is large: its 17 lines aren’t shown here.

libsec/genprime.c+27−0

This diff is large: its 28 lines aren’t shown here.

libsec/genrandom.c+62−0

This diff is large: its 63 lines aren’t shown here.

libsec/gensafeprime.c+36−0

This diff is large: its 37 lines aren’t shown here.

libsec/genstrongprime.c+57−0

This diff is large: its 58 lines aren’t shown here.

libsec/hmac.c+56−0

This diff is large: its 57 lines aren’t shown here.

libsec/hmactest.c+19−0

This diff is large: its 20 lines aren’t shown here.

libsec/md4.c+271−0

This diff is large: its 272 lines aren’t shown here.

libsec/md4test.c+31−0

This diff is large: its 32 lines aren’t shown here.

libsec/md5.c+148−0

This diff is large: its 149 lines aren’t shown here.

libsec/md5block.c+267−0

This diff is large: its 268 lines aren’t shown here.

libsec/md5pickle.c+37−0

This diff is large: its 38 lines aren’t shown here.

libsec/mkfile+55−0

This diff is large: its 56 lines aren’t shown here.

libsec/nfastrand.c+23−0

This diff is large: its 24 lines aren’t shown here.

libsec/os.h+2−0

This diff is large: its 3 lines aren’t shown here.

libsec/primetest.c+41−0

This diff is large: its 42 lines aren’t shown here.

libsec/prng.c+15−0

This diff is large: its 16 lines aren’t shown here.

libsec/probably_prime.c+84−0

This diff is large: its 85 lines aren’t shown here.

libsec/ranlib.core+0−0

Binary file not shown.

libsec/rc4.c+104−0

This diff is large: its 105 lines aren’t shown here.

libsec/readcert.c+50−0

This diff is large: its 51 lines aren’t shown here.

libsec/rsaalloc.c+52−0

This diff is large: its 53 lines aren’t shown here.

libsec/rsadecrypt.c+37−0

This diff is large: its 38 lines aren’t shown here.

libsec/rsaencrypt.c+12−0

This diff is large: its 13 lines aren’t shown here.

libsec/rsafill.c+61−0

This diff is large: its 62 lines aren’t shown here.

libsec/rsagen.c+82−0

This diff is large: its 83 lines aren’t shown here.

libsec/rsaprivtopub.c+16−0

This diff is large: its 17 lines aren’t shown here.

libsec/rsatest.c+57−0

This diff is large: its 58 lines aren’t shown here.

libsec/sha1.c+127−0

This diff is large: its 128 lines aren’t shown here.

libsec/sha1block.c+187−0

This diff is large: its 188 lines aren’t shown here.

libsec/sha1pickle.c+38−0

This diff is large: its 39 lines aren’t shown here.

libsec/smallprimes.c+1004−0

This diff is large: its 1005 lines aren’t shown here.

libsec/smallprimetest.c+1039−0

This diff is large: its 1040 lines aren’t shown here.

libsec/thumb.c+97−0

This diff is large: its 98 lines aren’t shown here.

libsec/tlshand.c+2291−0

This diff is large: its 2292 lines aren’t shown here.

libsec/x509.c+2520−0

This diff is large: its 2521 lines aren’t shown here.

main.c+126−0

This diff is large: its 127 lines aren’t shown here.

mkfile+95−0

This diff is large: its 96 lines aren’t shown here.

mkfile-Windows+54−0

This diff is large: its 55 lines aren’t shown here.

mkfile-posix+9−0

This diff is large: its 10 lines aren’t shown here.

mkone+50−0

This diff is large: its 51 lines aren’t shown here.

posix-386/Makefile+16−0

This diff is large: its 17 lines aren’t shown here.

posix-386/getcallerpc.c+8−0

This diff is large: its 9 lines aren’t shown here.

posix-386/md5block.s+241−0

This diff is large: its 242 lines aren’t shown here.

posix-386/sha1block.s+214−0

This diff is large: its 215 lines aren’t shown here.

posix-386/tas.c+23−0

This diff is large: its 24 lines aren’t shown here.

posix-power/Makefile+16−0

This diff is large: its 17 lines aren’t shown here.

posix-power/getcallerpc.c+8−0

This diff is large: its 9 lines aren’t shown here.

posix-power/tas.c+42−0

This diff is large: its 43 lines aren’t shown here.

readcons.c+110−0

This diff is large: its 111 lines aren’t shown here.

resource.h+16−0

This diff is large: its 17 lines aren’t shown here.

secstore.c+667−0

This diff is large: its 668 lines aren’t shown here.

win32-386/getcallerpc.c+8−0

This diff is large: its 9 lines aren’t shown here.

win32-386/md5block.s+241−0

This diff is large: its 242 lines aren’t shown here.

win32-386/mkfile+10−0

This diff is large: its 11 lines aren’t shown here.

win32-386/sha1block.s+214−0

This diff is large: its 215 lines aren’t shown here.

win32-386/tas.c+22−0

This diff is large: its 23 lines aren’t shown here.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t