Integrate unfix.org's IPv6 patches up to level 10, with rather a lot
[u/mdw/putty] / windows / winmisc.c
1 /*
2 * winmisc.c: miscellaneous Windows-specific things
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "putty.h"
8
9 OSVERSIONINFO osVersion;
10
11 void platform_get_x11_auth(char *display, int *proto,
12 unsigned char *data, int *datalen)
13 {
14 /* We don't support this at all under Windows. */
15 }
16
17 const char platform_x11_best_transport[] = "localhost";
18
19 char *platform_get_x_display(void) {
20 /* We may as well check for DISPLAY in case it's useful. */
21 return dupstr(getenv("DISPLAY"));
22 }
23
24 Filename filename_from_str(const char *str)
25 {
26 Filename ret;
27 strncpy(ret.path, str, sizeof(ret.path));
28 ret.path[sizeof(ret.path)-1] = '\0';
29 return ret;
30 }
31
32 const char *filename_to_str(const Filename *fn)
33 {
34 return fn->path;
35 }
36
37 int filename_equal(Filename f1, Filename f2)
38 {
39 return !strcmp(f1.path, f2.path);
40 }
41
42 int filename_is_null(Filename fn)
43 {
44 return !*fn.path;
45 }
46
47 char *get_username(void)
48 {
49 DWORD namelen;
50 char *user;
51
52 namelen = 0;
53 if (GetUserName(NULL, &namelen) == FALSE) {
54 /*
55 * Apparently this doesn't work at least on Windows XP SP2.
56 * Thus assume a maximum of 256. It will fail again if it
57 * doesn't fit.
58 */
59 namelen = 256;
60 }
61
62 user = snewn(namelen, char);
63 GetUserName(user, &namelen);
64
65 return user;
66 }
67
68 int SaneDialogBox(HINSTANCE hinst,
69 LPCTSTR tmpl,
70 HWND hwndparent,
71 DLGPROC lpDialogFunc)
72 {
73 WNDCLASS wc;
74 HWND hwnd;
75 MSG msg;
76 int flags;
77 int ret;
78 int gm;
79
80 wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
81 wc.lpfnWndProc = DefDlgProc;
82 wc.cbClsExtra = 0;
83 wc.cbWndExtra = DLGWINDOWEXTRA + 8;
84 wc.hInstance = hinst;
85 wc.hIcon = NULL;
86 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
87 wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1);
88 wc.lpszMenuName = NULL;
89 wc.lpszClassName = "PuTTYConfigBox";
90 RegisterClass(&wc);
91
92 hwnd = CreateDialog(hinst, tmpl, hwndparent, lpDialogFunc);
93
94 SetWindowLong(hwnd, BOXFLAGS, 0); /* flags */
95 SetWindowLong(hwnd, BOXRESULT, 0); /* result from SaneEndDialog */
96
97 while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
98 flags=GetWindowLong(hwnd, BOXFLAGS);
99 if (!(flags & DF_END) && !IsDialogMessage(hwnd, &msg))
100 DispatchMessage(&msg);
101 if (flags & DF_END)
102 break;
103 }
104
105 if (gm == 0)
106 PostQuitMessage(msg.wParam); /* We got a WM_QUIT, pass it on */
107
108 ret=GetWindowLong(hwnd, BOXRESULT);
109 DestroyWindow(hwnd);
110 return ret;
111 }
112
113 void SaneEndDialog(HWND hwnd, int ret)
114 {
115 SetWindowLong(hwnd, BOXRESULT, ret);
116 SetWindowLong(hwnd, BOXFLAGS, DF_END);
117 }
118
119 BOOL init_winver(void)
120 {
121 ZeroMemory(&osVersion, sizeof(osVersion));
122 osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
123 return GetVersionEx ( (OSVERSIONINFO *) &osVersion);
124 }
125
126 #ifdef DEBUG
127 static FILE *debug_fp = NULL;
128 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
129 static int debug_got_console = 0;
130
131 void dputs(char *buf)
132 {
133 DWORD dw;
134
135 if (!debug_got_console) {
136 if (AllocConsole()) {
137 debug_got_console = 1;
138 debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
139 }
140 }
141 if (!debug_fp) {
142 debug_fp = fopen("debug.log", "w");
143 }
144
145 if (debug_hdl != INVALID_HANDLE_VALUE) {
146 WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
147 }
148 fputs(buf, debug_fp);
149 fflush(debug_fp);
150 }
151 #endif
152
153 #ifdef MINEFIELD
154 /*
155 * Minefield - a Windows equivalent for Electric Fence
156 */
157
158 #define PAGESIZE 4096
159
160 /*
161 * Design:
162 *
163 * We start by reserving as much virtual address space as Windows
164 * will sensibly (or not sensibly) let us have. We flag it all as
165 * invalid memory.
166 *
167 * Any allocation attempt is satisfied by committing one or more
168 * pages, with an uncommitted page on either side. The returned
169 * memory region is jammed up against the _end_ of the pages.
170 *
171 * Freeing anything causes instantaneous decommitment of the pages
172 * involved, so stale pointers are caught as soon as possible.
173 */
174
175 static int minefield_initialised = 0;
176 static void *minefield_region = NULL;
177 static long minefield_size = 0;
178 static long minefield_npages = 0;
179 static long minefield_curpos = 0;
180 static unsigned short *minefield_admin = NULL;
181 static void *minefield_pages = NULL;
182
183 static void minefield_admin_hide(int hide)
184 {
185 int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
186 VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
187 }
188
189 static void minefield_init(void)
190 {
191 int size;
192 int admin_size;
193 int i;
194
195 for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
196 minefield_region = VirtualAlloc(NULL, size,
197 MEM_RESERVE, PAGE_NOACCESS);
198 if (minefield_region)
199 break;
200 }
201 minefield_size = size;
202
203 /*
204 * Firstly, allocate a section of that to be the admin block.
205 * We'll need a two-byte field for each page.
206 */
207 minefield_admin = minefield_region;
208 minefield_npages = minefield_size / PAGESIZE;
209 admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
210 minefield_npages = (minefield_size - admin_size) / PAGESIZE;
211 minefield_pages = (char *) minefield_region + admin_size;
212
213 /*
214 * Commit the admin region.
215 */
216 VirtualAlloc(minefield_admin, minefield_npages * 2,
217 MEM_COMMIT, PAGE_READWRITE);
218
219 /*
220 * Mark all pages as unused (0xFFFF).
221 */
222 for (i = 0; i < minefield_npages; i++)
223 minefield_admin[i] = 0xFFFF;
224
225 /*
226 * Hide the admin region.
227 */
228 minefield_admin_hide(1);
229
230 minefield_initialised = 1;
231 }
232
233 static void minefield_bomb(void)
234 {
235 div(1, *(int *) minefield_pages);
236 }
237
238 static void *minefield_alloc(int size)
239 {
240 int npages;
241 int pos, lim, region_end, region_start;
242 int start;
243 int i;
244
245 npages = (size + PAGESIZE - 1) / PAGESIZE;
246
247 minefield_admin_hide(0);
248
249 /*
250 * Search from current position until we find a contiguous
251 * bunch of npages+2 unused pages.
252 */
253 pos = minefield_curpos;
254 lim = minefield_npages;
255 while (1) {
256 /* Skip over used pages. */
257 while (pos < lim && minefield_admin[pos] != 0xFFFF)
258 pos++;
259 /* Count unused pages. */
260 start = pos;
261 while (pos < lim && pos - start < npages + 2 &&
262 minefield_admin[pos] == 0xFFFF)
263 pos++;
264 if (pos - start == npages + 2)
265 break;
266 /* If we've reached the limit, reset the limit or stop. */
267 if (pos >= lim) {
268 if (lim == minefield_npages) {
269 /* go round and start again at zero */
270 lim = minefield_curpos;
271 pos = 0;
272 } else {
273 minefield_admin_hide(1);
274 return NULL;
275 }
276 }
277 }
278
279 minefield_curpos = pos - 1;
280
281 /*
282 * We have npages+2 unused pages starting at start. We leave
283 * the first and last of these alone and use the rest.
284 */
285 region_end = (start + npages + 1) * PAGESIZE;
286 region_start = region_end - size;
287 /* FIXME: could align here if we wanted */
288
289 /*
290 * Update the admin region.
291 */
292 for (i = start + 2; i < start + npages + 1; i++)
293 minefield_admin[i] = 0xFFFE; /* used but no region starts here */
294 minefield_admin[start + 1] = region_start % PAGESIZE;
295
296 minefield_admin_hide(1);
297
298 VirtualAlloc((char *) minefield_pages + region_start, size,
299 MEM_COMMIT, PAGE_READWRITE);
300 return (char *) minefield_pages + region_start;
301 }
302
303 static void minefield_free(void *ptr)
304 {
305 int region_start, i, j;
306
307 minefield_admin_hide(0);
308
309 region_start = (char *) ptr - (char *) minefield_pages;
310 i = region_start / PAGESIZE;
311 if (i < 0 || i >= minefield_npages ||
312 minefield_admin[i] != region_start % PAGESIZE)
313 minefield_bomb();
314 for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
315 minefield_admin[j] = 0xFFFF;
316 }
317
318 VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
319
320 minefield_admin_hide(1);
321 }
322
323 static int minefield_get_size(void *ptr)
324 {
325 int region_start, i, j;
326
327 minefield_admin_hide(0);
328
329 region_start = (char *) ptr - (char *) minefield_pages;
330 i = region_start / PAGESIZE;
331 if (i < 0 || i >= minefield_npages ||
332 minefield_admin[i] != region_start % PAGESIZE)
333 minefield_bomb();
334 for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
335
336 minefield_admin_hide(1);
337
338 return j * PAGESIZE - region_start;
339 }
340
341 void *minefield_c_malloc(size_t size)
342 {
343 if (!minefield_initialised)
344 minefield_init();
345 return minefield_alloc(size);
346 }
347
348 void minefield_c_free(void *p)
349 {
350 if (!minefield_initialised)
351 minefield_init();
352 minefield_free(p);
353 }
354
355 /*
356 * realloc _always_ moves the chunk, for rapid detection of code
357 * that assumes it won't.
358 */
359 void *minefield_c_realloc(void *p, size_t size)
360 {
361 size_t oldsize;
362 void *q;
363 if (!minefield_initialised)
364 minefield_init();
365 q = minefield_alloc(size);
366 oldsize = minefield_get_size(p);
367 memcpy(q, p, (oldsize < size ? oldsize : size));
368 minefield_free(p);
369 return q;
370 }
371
372 #endif /* MINEFIELD */