Move SaneDialogBox()/SaneEndDialog() from winmisc.c to windlg.c, since they
[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 BOOL init_winver(void)
69 {
70 ZeroMemory(&osVersion, sizeof(osVersion));
71 osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
72 return GetVersionEx ( (OSVERSIONINFO *) &osVersion);
73 }
74
75 #ifdef DEBUG
76 static FILE *debug_fp = NULL;
77 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
78 static int debug_got_console = 0;
79
80 void dputs(char *buf)
81 {
82 DWORD dw;
83
84 if (!debug_got_console) {
85 if (AllocConsole()) {
86 debug_got_console = 1;
87 debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
88 }
89 }
90 if (!debug_fp) {
91 debug_fp = fopen("debug.log", "w");
92 }
93
94 if (debug_hdl != INVALID_HANDLE_VALUE) {
95 WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
96 }
97 fputs(buf, debug_fp);
98 fflush(debug_fp);
99 }
100 #endif
101
102 #ifdef MINEFIELD
103 /*
104 * Minefield - a Windows equivalent for Electric Fence
105 */
106
107 #define PAGESIZE 4096
108
109 /*
110 * Design:
111 *
112 * We start by reserving as much virtual address space as Windows
113 * will sensibly (or not sensibly) let us have. We flag it all as
114 * invalid memory.
115 *
116 * Any allocation attempt is satisfied by committing one or more
117 * pages, with an uncommitted page on either side. The returned
118 * memory region is jammed up against the _end_ of the pages.
119 *
120 * Freeing anything causes instantaneous decommitment of the pages
121 * involved, so stale pointers are caught as soon as possible.
122 */
123
124 static int minefield_initialised = 0;
125 static void *minefield_region = NULL;
126 static long minefield_size = 0;
127 static long minefield_npages = 0;
128 static long minefield_curpos = 0;
129 static unsigned short *minefield_admin = NULL;
130 static void *minefield_pages = NULL;
131
132 static void minefield_admin_hide(int hide)
133 {
134 int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
135 VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
136 }
137
138 static void minefield_init(void)
139 {
140 int size;
141 int admin_size;
142 int i;
143
144 for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
145 minefield_region = VirtualAlloc(NULL, size,
146 MEM_RESERVE, PAGE_NOACCESS);
147 if (minefield_region)
148 break;
149 }
150 minefield_size = size;
151
152 /*
153 * Firstly, allocate a section of that to be the admin block.
154 * We'll need a two-byte field for each page.
155 */
156 minefield_admin = minefield_region;
157 minefield_npages = minefield_size / PAGESIZE;
158 admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
159 minefield_npages = (minefield_size - admin_size) / PAGESIZE;
160 minefield_pages = (char *) minefield_region + admin_size;
161
162 /*
163 * Commit the admin region.
164 */
165 VirtualAlloc(minefield_admin, minefield_npages * 2,
166 MEM_COMMIT, PAGE_READWRITE);
167
168 /*
169 * Mark all pages as unused (0xFFFF).
170 */
171 for (i = 0; i < minefield_npages; i++)
172 minefield_admin[i] = 0xFFFF;
173
174 /*
175 * Hide the admin region.
176 */
177 minefield_admin_hide(1);
178
179 minefield_initialised = 1;
180 }
181
182 static void minefield_bomb(void)
183 {
184 div(1, *(int *) minefield_pages);
185 }
186
187 static void *minefield_alloc(int size)
188 {
189 int npages;
190 int pos, lim, region_end, region_start;
191 int start;
192 int i;
193
194 npages = (size + PAGESIZE - 1) / PAGESIZE;
195
196 minefield_admin_hide(0);
197
198 /*
199 * Search from current position until we find a contiguous
200 * bunch of npages+2 unused pages.
201 */
202 pos = minefield_curpos;
203 lim = minefield_npages;
204 while (1) {
205 /* Skip over used pages. */
206 while (pos < lim && minefield_admin[pos] != 0xFFFF)
207 pos++;
208 /* Count unused pages. */
209 start = pos;
210 while (pos < lim && pos - start < npages + 2 &&
211 minefield_admin[pos] == 0xFFFF)
212 pos++;
213 if (pos - start == npages + 2)
214 break;
215 /* If we've reached the limit, reset the limit or stop. */
216 if (pos >= lim) {
217 if (lim == minefield_npages) {
218 /* go round and start again at zero */
219 lim = minefield_curpos;
220 pos = 0;
221 } else {
222 minefield_admin_hide(1);
223 return NULL;
224 }
225 }
226 }
227
228 minefield_curpos = pos - 1;
229
230 /*
231 * We have npages+2 unused pages starting at start. We leave
232 * the first and last of these alone and use the rest.
233 */
234 region_end = (start + npages + 1) * PAGESIZE;
235 region_start = region_end - size;
236 /* FIXME: could align here if we wanted */
237
238 /*
239 * Update the admin region.
240 */
241 for (i = start + 2; i < start + npages + 1; i++)
242 minefield_admin[i] = 0xFFFE; /* used but no region starts here */
243 minefield_admin[start + 1] = region_start % PAGESIZE;
244
245 minefield_admin_hide(1);
246
247 VirtualAlloc((char *) minefield_pages + region_start, size,
248 MEM_COMMIT, PAGE_READWRITE);
249 return (char *) minefield_pages + region_start;
250 }
251
252 static void minefield_free(void *ptr)
253 {
254 int region_start, i, j;
255
256 minefield_admin_hide(0);
257
258 region_start = (char *) ptr - (char *) minefield_pages;
259 i = region_start / PAGESIZE;
260 if (i < 0 || i >= minefield_npages ||
261 minefield_admin[i] != region_start % PAGESIZE)
262 minefield_bomb();
263 for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
264 minefield_admin[j] = 0xFFFF;
265 }
266
267 VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
268
269 minefield_admin_hide(1);
270 }
271
272 static int minefield_get_size(void *ptr)
273 {
274 int region_start, i, j;
275
276 minefield_admin_hide(0);
277
278 region_start = (char *) ptr - (char *) minefield_pages;
279 i = region_start / PAGESIZE;
280 if (i < 0 || i >= minefield_npages ||
281 minefield_admin[i] != region_start % PAGESIZE)
282 minefield_bomb();
283 for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
284
285 minefield_admin_hide(1);
286
287 return j * PAGESIZE - region_start;
288 }
289
290 void *minefield_c_malloc(size_t size)
291 {
292 if (!minefield_initialised)
293 minefield_init();
294 return minefield_alloc(size);
295 }
296
297 void minefield_c_free(void *p)
298 {
299 if (!minefield_initialised)
300 minefield_init();
301 minefield_free(p);
302 }
303
304 /*
305 * realloc _always_ moves the chunk, for rapid detection of code
306 * that assumes it won't.
307 */
308 void *minefield_c_realloc(void *p, size_t size)
309 {
310 size_t oldsize;
311 void *q;
312 if (!minefield_initialised)
313 minefield_init();
314 q = minefield_alloc(size);
315 oldsize = minefield_get_size(p);
316 memcpy(q, p, (oldsize < size ? oldsize : size));
317 minefield_free(p);
318 return q;
319 }
320
321 #endif /* MINEFIELD */