2 * winmisc.c: miscellaneous Windows-specific things
11 OSVERSIONINFO osVersion;
13 char *platform_get_x_display(void) {
14 /* We may as well check for DISPLAY in case it's useful. */
15 return dupstr(getenv("DISPLAY"));
18 Filename *filename_from_str(const char *str)
20 Filename *ret = snew(Filename);
21 ret->path = dupstr(str);
25 Filename *filename_copy(const Filename *fn)
27 return filename_from_str(fn->path);
30 const char *filename_to_str(const Filename *fn)
35 int filename_equal(const Filename *f1, const Filename *f2)
37 return !strcmp(f1->path, f2->path);
40 int filename_is_null(const Filename *fn)
45 void filename_free(Filename *fn)
51 int filename_serialise(const Filename *f, void *vdata)
53 char *data = (char *)vdata;
54 int len = strlen(f->path) + 1; /* include trailing NUL */
56 strcpy(data, f->path);
60 Filename *filename_deserialise(void *vdata, int maxsize, int *used)
62 char *data = (char *)vdata;
64 end = memchr(data, '\0', maxsize);
69 return filename_from_str(data);
72 #ifndef NO_SECUREZEROMEMORY
74 * Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
76 void smemclr(void *b, size_t n) {
78 SecureZeroMemory(b, n);
82 char *get_username(void)
86 int got_username = FALSE;
87 DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA,
88 (EXTENDED_NAME_FORMAT, LPSTR, PULONG));
91 static int tried_usernameex = FALSE;
92 if (!tried_usernameex) {
93 /* Not available on Win9x, so load dynamically */
94 HMODULE secur32 = load_system32_dll("secur32.dll");
95 GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);
96 tried_usernameex = TRUE;
100 if (p_GetUserNameExA) {
102 * If available, use the principal -- this avoids the problem
103 * that the local username is case-insensitive but Kerberos
104 * usernames are case-sensitive.
109 (void) p_GetUserNameExA(NameUserPrincipal, NULL, &namelen);
111 user = snewn(namelen, char);
112 got_username = p_GetUserNameExA(NameUserPrincipal, user, &namelen);
114 char *p = strchr(user, '@');
122 /* Fall back to local user name */
124 if (GetUserName(NULL, &namelen) == FALSE) {
126 * Apparently this doesn't work at least on Windows XP SP2.
127 * Thus assume a maximum of 256. It will fail again if it
133 user = snewn(namelen, char);
134 got_username = GetUserName(user, &namelen);
140 return got_username ? user : NULL;
143 BOOL init_winver(void)
145 ZeroMemory(&osVersion, sizeof(osVersion));
146 osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
147 return GetVersionEx ( (OSVERSIONINFO *) &osVersion);
150 HMODULE load_system32_dll(const char *libname)
153 * Wrapper function to load a DLL out of c:\windows\system32
154 * without going through the full DLL search path. (Hence no
155 * attack is possible by placing a substitute DLL earlier on that
158 static char *sysdir = NULL;
165 size = 3*size/2 + 512;
166 sysdir = sresize(sysdir, size, char);
167 len = GetSystemDirectory(sysdir, size);
168 } while (len >= size);
171 fullpath = dupcat(sysdir, "\\", libname, NULL);
172 ret = LoadLibrary(fullpath);
178 * A tree234 containing mappings from system error codes to strings.
186 static int errstring_find(void *av, void *bv)
189 struct errstring *b = (struct errstring *)bv;
196 static int errstring_compare(void *av, void *bv)
198 struct errstring *a = (struct errstring *)av;
199 return errstring_find(&a->error, bv);
202 static tree234 *errstrings = NULL;
204 const char *win_strerror(int error)
206 struct errstring *es;
209 errstrings = newtree234(errstring_compare);
211 es = find234(errstrings, &error, errstring_find);
214 char msgtext[65536]; /* maximum size for FormatMessage is 64K */
216 es = snew(struct errstring);
218 if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
219 FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,
220 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
221 msgtext, lenof(msgtext)-1, NULL)) {
223 "(unable to format: FormatMessage returned %d)",
226 int len = strlen(msgtext);
227 if (len > 0 && msgtext[len-1] == '\n')
228 msgtext[len-1] = '\0';
230 es->text = dupprintf("Error %d: %s", error, msgtext);
231 add234(errstrings, es);
238 static FILE *debug_fp = NULL;
239 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
240 static int debug_got_console = 0;
242 void dputs(const char *buf)
246 if (!debug_got_console) {
247 if (AllocConsole()) {
248 debug_got_console = 1;
249 debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
253 debug_fp = fopen("debug.log", "w");
256 if (debug_hdl != INVALID_HANDLE_VALUE) {
257 WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
259 fputs(buf, debug_fp);
266 * Minefield - a Windows equivalent for Electric Fence
269 #define PAGESIZE 4096
274 * We start by reserving as much virtual address space as Windows
275 * will sensibly (or not sensibly) let us have. We flag it all as
278 * Any allocation attempt is satisfied by committing one or more
279 * pages, with an uncommitted page on either side. The returned
280 * memory region is jammed up against the _end_ of the pages.
282 * Freeing anything causes instantaneous decommitment of the pages
283 * involved, so stale pointers are caught as soon as possible.
286 static int minefield_initialised = 0;
287 static void *minefield_region = NULL;
288 static long minefield_size = 0;
289 static long minefield_npages = 0;
290 static long minefield_curpos = 0;
291 static unsigned short *minefield_admin = NULL;
292 static void *minefield_pages = NULL;
294 static void minefield_admin_hide(int hide)
296 int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
297 VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
300 static void minefield_init(void)
306 for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
307 minefield_region = VirtualAlloc(NULL, size,
308 MEM_RESERVE, PAGE_NOACCESS);
309 if (minefield_region)
312 minefield_size = size;
315 * Firstly, allocate a section of that to be the admin block.
316 * We'll need a two-byte field for each page.
318 minefield_admin = minefield_region;
319 minefield_npages = minefield_size / PAGESIZE;
320 admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
321 minefield_npages = (minefield_size - admin_size) / PAGESIZE;
322 minefield_pages = (char *) minefield_region + admin_size;
325 * Commit the admin region.
327 VirtualAlloc(minefield_admin, minefield_npages * 2,
328 MEM_COMMIT, PAGE_READWRITE);
331 * Mark all pages as unused (0xFFFF).
333 for (i = 0; i < minefield_npages; i++)
334 minefield_admin[i] = 0xFFFF;
337 * Hide the admin region.
339 minefield_admin_hide(1);
341 minefield_initialised = 1;
344 static void minefield_bomb(void)
346 div(1, *(int *) minefield_pages);
349 static void *minefield_alloc(int size)
352 int pos, lim, region_end, region_start;
356 npages = (size + PAGESIZE - 1) / PAGESIZE;
358 minefield_admin_hide(0);
361 * Search from current position until we find a contiguous
362 * bunch of npages+2 unused pages.
364 pos = minefield_curpos;
365 lim = minefield_npages;
367 /* Skip over used pages. */
368 while (pos < lim && minefield_admin[pos] != 0xFFFF)
370 /* Count unused pages. */
372 while (pos < lim && pos - start < npages + 2 &&
373 minefield_admin[pos] == 0xFFFF)
375 if (pos - start == npages + 2)
377 /* If we've reached the limit, reset the limit or stop. */
379 if (lim == minefield_npages) {
380 /* go round and start again at zero */
381 lim = minefield_curpos;
384 minefield_admin_hide(1);
390 minefield_curpos = pos - 1;
393 * We have npages+2 unused pages starting at start. We leave
394 * the first and last of these alone and use the rest.
396 region_end = (start + npages + 1) * PAGESIZE;
397 region_start = region_end - size;
398 /* FIXME: could align here if we wanted */
401 * Update the admin region.
403 for (i = start + 2; i < start + npages + 1; i++)
404 minefield_admin[i] = 0xFFFE; /* used but no region starts here */
405 minefield_admin[start + 1] = region_start % PAGESIZE;
407 minefield_admin_hide(1);
409 VirtualAlloc((char *) minefield_pages + region_start, size,
410 MEM_COMMIT, PAGE_READWRITE);
411 return (char *) minefield_pages + region_start;
414 static void minefield_free(void *ptr)
416 int region_start, i, j;
418 minefield_admin_hide(0);
420 region_start = (char *) ptr - (char *) minefield_pages;
421 i = region_start / PAGESIZE;
422 if (i < 0 || i >= minefield_npages ||
423 minefield_admin[i] != region_start % PAGESIZE)
425 for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
426 minefield_admin[j] = 0xFFFF;
429 VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
431 minefield_admin_hide(1);
434 static int minefield_get_size(void *ptr)
436 int region_start, i, j;
438 minefield_admin_hide(0);
440 region_start = (char *) ptr - (char *) minefield_pages;
441 i = region_start / PAGESIZE;
442 if (i < 0 || i >= minefield_npages ||
443 minefield_admin[i] != region_start % PAGESIZE)
445 for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
447 minefield_admin_hide(1);
449 return j * PAGESIZE - region_start;
452 void *minefield_c_malloc(size_t size)
454 if (!minefield_initialised)
456 return minefield_alloc(size);
459 void minefield_c_free(void *p)
461 if (!minefield_initialised)
467 * realloc _always_ moves the chunk, for rapid detection of code
468 * that assumes it won't.
470 void *minefield_c_realloc(void *p, size_t size)
474 if (!minefield_initialised)
476 q = minefield_alloc(size);
477 oldsize = minefield_get_size(p);
478 memcpy(q, p, (oldsize < size ? oldsize : size));
483 #endif /* MINEFIELD */
485 FontSpec *fontspec_new(const char *name,
486 int bold, int height, int charset)
488 FontSpec *f = snew(FontSpec);
489 f->name = dupstr(name);
492 f->charset = charset;
495 FontSpec *fontspec_copy(const FontSpec *f)
497 return fontspec_new(f->name, f->isbold, f->height, f->charset);
499 void fontspec_free(FontSpec *f)
504 int fontspec_serialise(FontSpec *f, void *vdata)
506 char *data = (char *)vdata;
507 int len = strlen(f->name) + 1; /* include trailing NUL */
509 strcpy(data, f->name);
510 PUT_32BIT_MSB_FIRST(data + len, f->isbold);
511 PUT_32BIT_MSB_FIRST(data + len + 4, f->height);
512 PUT_32BIT_MSB_FIRST(data + len + 8, f->charset);
514 return len + 12; /* also include three 4-byte ints */
516 FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used)
518 char *data = (char *)vdata;
522 end = memchr(data, '\0', maxsize-12);
526 *used = end - data + 12;
527 return fontspec_new(data,
528 GET_32BIT_MSB_FIRST(end),
529 GET_32BIT_MSB_FIRST(end + 4),
530 GET_32BIT_MSB_FIRST(end + 8));