/src/libgpg-error/src/init.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* init.c - Initialize the GnuPG error library. |
2 | | Copyright (C) 2005, 2010 g10 Code GmbH |
3 | | |
4 | | This file is part of libgpg-error. |
5 | | |
6 | | libgpg-error is free software; you can redistribute it and/or |
7 | | modify it under the terms of the GNU Lesser General Public License |
8 | | as published by the Free Software Foundation; either version 2.1 of |
9 | | the License, or (at your option) any later version. |
10 | | |
11 | | libgpg-error is distributed in the hope that it will be useful, but |
12 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | Lesser General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU Lesser General Public |
17 | | License along with this program; if not, see <https://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #if HAVE_CONFIG_H |
21 | | #include <config.h> |
22 | | #endif |
23 | | |
24 | | #include <stdlib.h> |
25 | | #include <stdio.h> |
26 | | #include <string.h> |
27 | | #include <errno.h> |
28 | | |
29 | | #include "gpgrt-int.h" |
30 | | #include "gettext.h" |
31 | | #include "init.h" |
32 | | |
33 | | |
34 | | /* Locale directory support. */ |
35 | | |
36 | | #if HAVE_W32_SYSTEM |
37 | | |
38 | | #include <windows.h> |
39 | | |
40 | | static int tls_index = TLS_OUT_OF_INDEXES; /* Index for the TLS functions. */ |
41 | | |
42 | | static char *get_locale_dir (void); |
43 | | static void drop_locale_dir (char *locale_dir); |
44 | | |
45 | | #else /*!HAVE_W32_SYSTEM*/ |
46 | | |
47 | 8 | #define get_locale_dir() LOCALEDIR |
48 | | #define drop_locale_dir(dir) |
49 | | |
50 | | #endif /*!HAVE_W32_SYSTEM*/ |
51 | | |
52 | | |
53 | | /* The list of emergency cleanup functions; see _gpgrt_abort and |
54 | | * _gpgrt_add_emergency_cleanup. */ |
55 | | struct emergency_cleanup_item_s; |
56 | | typedef struct emergency_cleanup_item_s *emergency_cleanup_item_t; |
57 | | struct emergency_cleanup_item_s |
58 | | { |
59 | | emergency_cleanup_item_t next; |
60 | | void (*func) (void); |
61 | | }; |
62 | | static emergency_cleanup_item_t emergency_cleanup_list; |
63 | | |
64 | | |
65 | | |
66 | | |
67 | | /* The realloc function as set by gpgrt_set_alloc_func. */ |
68 | | static void *(*custom_realloc)(void *a, size_t n); |
69 | | |
70 | | |
71 | | |
72 | | static void |
73 | | real_init (void) |
74 | 8 | { |
75 | 8 | #ifdef ENABLE_NLS |
76 | 8 | char *locale_dir; |
77 | | |
78 | | /* We only have to bind our locale directory to our text domain. */ |
79 | 8 | locale_dir = get_locale_dir (); |
80 | 8 | if (locale_dir) |
81 | 8 | { |
82 | 8 | bindtextdomain (PACKAGE, locale_dir); |
83 | 8 | drop_locale_dir (locale_dir); |
84 | 8 | } |
85 | 8 | #endif |
86 | 8 | _gpgrt_estream_init (); |
87 | 8 | } |
88 | | |
89 | | /* Initialize the library. This function should be run early. */ |
90 | | gpg_error_t |
91 | | _gpg_err_init (void) |
92 | 8 | { |
93 | | #ifdef HAVE_W32_SYSTEM |
94 | | # ifdef DLL_EXPORT |
95 | | /* We always have a constructor and thus this function is called |
96 | | automatically. Due to the way the C init code of mingw works, |
97 | | the constructors are called before our DllMain function is |
98 | | called. The problem with that is that the TLS has not been setup |
99 | | and w32-gettext.c requires TLS. To solve this we do nothing here |
100 | | but call the actual init code from our DllMain. */ |
101 | | # else /*!DLL_EXPORT*/ |
102 | | /* Note that if the TLS is actually used, we can't release the TLS |
103 | | as there is no way to know when a thread terminates (i.e. no |
104 | | thread-specific-atexit). You are really better off to use the |
105 | | DLL! */ |
106 | | if (tls_index == TLS_OUT_OF_INDEXES) |
107 | | { |
108 | | tls_index = TlsAlloc (); |
109 | | if (tls_index == TLS_OUT_OF_INDEXES) |
110 | | { |
111 | | /* No way to continue - commit suicide. */ |
112 | | _gpgrt_abort (); |
113 | | } |
114 | | _gpg_w32__init_gettext_module (); |
115 | | real_init (); |
116 | | } |
117 | | # endif /*!DLL_EXPORT*/ |
118 | | #else |
119 | 8 | real_init (); |
120 | 8 | #endif |
121 | 8 | return 0; |
122 | 8 | } |
123 | | |
124 | | |
125 | | /* Deinitialize libgpg-error. This function is only used in special |
126 | | circumstances. No gpg-error function should be used after this |
127 | | function has been called. A value of 0 passed for MODE |
128 | | deinitializes the entire libgpg-error, a value of 1 releases |
129 | | resources allocated for the current thread and only that thread may |
130 | | not anymore access libgpg-error after such a call. Under Windows |
131 | | this function may be called from the DllMain function of a DLL |
132 | | which statically links to libgpg-error. */ |
133 | | void |
134 | | _gpg_err_deinit (int mode) |
135 | 0 | { |
136 | | #if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT) |
137 | | struct tls_space_s *tls; |
138 | | |
139 | | tls = TlsGetValue (tls_index); |
140 | | if (tls) |
141 | | { |
142 | | TlsSetValue (tls_index, NULL); |
143 | | LocalFree (tls); |
144 | | } |
145 | | |
146 | | if (mode == 0) |
147 | | { |
148 | | TlsFree (tls_index); |
149 | | tls_index = TLS_OUT_OF_INDEXES; |
150 | | } |
151 | | #else |
152 | 0 | (void)mode; |
153 | 0 | #endif |
154 | 0 | } |
155 | | |
156 | | |
157 | | /* Add the emergency cleanup function F to the list of those function. |
158 | | * If the a function with that address has already been registered, it |
159 | | * is not added a second time. These emergency functions are called |
160 | | * whenever gpgrt_abort is called and at no other place. Like signal |
161 | | * handles the emergency cleanup functions shall not call any |
162 | | * non-trivial functions and return as soon as possible. They allow |
163 | | * to cleanup internal states which should not go into a core dumps or |
164 | | * similar. This is independent of any atexit functions. We don't |
165 | | * use locks here because in an emergency case we can't use them |
166 | | * anyway. */ |
167 | | void |
168 | | _gpgrt_add_emergency_cleanup (void (*f)(void)) |
169 | 0 | { |
170 | 0 | emergency_cleanup_item_t item; |
171 | |
|
172 | 0 | for (item = emergency_cleanup_list; item; item = item->next) |
173 | 0 | if (item->func == f) |
174 | 0 | return; /* Function has already been registered. */ |
175 | | |
176 | | /* We use a standard malloc here. */ |
177 | 0 | item = malloc (sizeof *item); |
178 | 0 | if (item) |
179 | 0 | { |
180 | 0 | item->func = f; |
181 | 0 | item->next = emergency_cleanup_list; |
182 | 0 | emergency_cleanup_list = item; |
183 | 0 | } |
184 | 0 | else |
185 | 0 | _gpgrt_log_fatal ("out of core in gpgrt_add_emergency_cleanup\n"); |
186 | 0 | } |
187 | | |
188 | | |
189 | | /* Run the emergency handlers. No locks are used because we are anyway |
190 | | * in an emergency state. We also can't release any memory. */ |
191 | | static void |
192 | | run_emergency_cleanup (void) |
193 | 0 | { |
194 | 0 | emergency_cleanup_item_t next; |
195 | 0 | void (*f)(void); |
196 | |
|
197 | 0 | while (emergency_cleanup_list) |
198 | 0 | { |
199 | 0 | next = emergency_cleanup_list->next; |
200 | 0 | f = emergency_cleanup_list->func; |
201 | 0 | emergency_cleanup_list->func = NULL; |
202 | 0 | emergency_cleanup_list = next; |
203 | 0 | if (f) |
204 | 0 | f (); |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | |
209 | | /* Wrapper around abort to be able to run all emergency cleanup |
210 | | * functions. */ |
211 | | void |
212 | | _gpgrt_abort (void) |
213 | 0 | { |
214 | 0 | run_emergency_cleanup (); |
215 | 0 | abort (); |
216 | 0 | } |
217 | | |
218 | | |
219 | | |
220 | | /* Register F as allocation function. This function is used for all |
221 | | APIs which return an allocated buffer. F needs to have standard |
222 | | realloc semantics. It should be called as early as possible and |
223 | | not changed later. */ |
224 | | void |
225 | | _gpgrt_set_alloc_func (void *(*f)(void *a, size_t n)) |
226 | 0 | { |
227 | 0 | custom_realloc = f; |
228 | 0 | } |
229 | | |
230 | | |
231 | | /* The realloc to be used for data returned by the public API. */ |
232 | | void * |
233 | | _gpgrt_realloc (void *a, size_t n) |
234 | 694k | { |
235 | 694k | if (custom_realloc) |
236 | 0 | return custom_realloc (a, n); |
237 | | |
238 | 694k | if (!n) |
239 | 346k | { |
240 | 346k | free (a); |
241 | 346k | return NULL; |
242 | 346k | } |
243 | | |
244 | 348k | if (!a) |
245 | 348k | return malloc (n); |
246 | | |
247 | 0 | return realloc (a, n); |
248 | 348k | } |
249 | | |
250 | | |
251 | | /* This is safe version of realloc useful for reallocing a calloced |
252 | | * array. There are two ways to call it: The first example |
253 | | * reallocates the array A to N elements each of SIZE but does not |
254 | | * clear the newly allocated elements: |
255 | | * |
256 | | * p = gpgrt_reallocarray (a, n, n, nsize); |
257 | | * |
258 | | * Note that when NOLD is larger than N no cleaning is needed anyway. |
259 | | * The second example reallocates an array of size NOLD to N elements |
260 | | * each of SIZE but clear the newly allocated elements: |
261 | | * |
262 | | * p = gpgrt_reallocarray (a, nold, n, nsize); |
263 | | * |
264 | | * Note that gpgrt_reallocarray (NULL, 0, n, nsize) is equivalent to |
265 | | * _gpgrt_calloc (n, nsize). |
266 | | * |
267 | | */ |
268 | | void * |
269 | | _gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size) |
270 | 0 | { |
271 | 0 | size_t oldbytes, bytes; |
272 | 0 | char *p; |
273 | |
|
274 | 0 | bytes = nmemb * size; /* size_t is unsigned so the behavior on overflow |
275 | | * is defined. */ |
276 | 0 | if (size && bytes / size != nmemb) |
277 | 0 | { |
278 | 0 | _gpg_err_set_errno (ENOMEM); |
279 | 0 | return NULL; |
280 | 0 | } |
281 | | |
282 | 0 | p = _gpgrt_realloc (a, bytes); |
283 | 0 | if (p && oldnmemb < nmemb) |
284 | 0 | { |
285 | | /* OLDNMEMBS is lower than NMEMB thus the user asked for a |
286 | | calloc. Clear all newly allocated members. */ |
287 | 0 | oldbytes = oldnmemb * size; |
288 | 0 | if (size && oldbytes / size != oldnmemb) |
289 | 0 | { |
290 | 0 | xfree (p); |
291 | 0 | _gpg_err_set_errno (ENOMEM); |
292 | 0 | return NULL; |
293 | 0 | } |
294 | 0 | memset (p + oldbytes, 0, bytes - oldbytes); |
295 | 0 | } |
296 | 0 | return p; |
297 | 0 | } |
298 | | |
299 | | |
300 | | /* The malloc to be used for data returned by the public API. */ |
301 | | void * |
302 | | _gpgrt_malloc (size_t n) |
303 | 346k | { |
304 | 346k | if (!n) |
305 | 0 | n++; |
306 | 346k | return _gpgrt_realloc (NULL, n); |
307 | 346k | } |
308 | | |
309 | | |
310 | | void * |
311 | | _gpgrt_calloc (size_t n, size_t m) |
312 | 0 | { |
313 | 0 | size_t bytes; |
314 | 0 | void *p; |
315 | |
|
316 | 0 | bytes = n * m; /* size_t is unsigned so the behavior on overflow is |
317 | | defined. */ |
318 | 0 | if (m && bytes / m != n) |
319 | 0 | { |
320 | 0 | _gpg_err_set_errno (ENOMEM); |
321 | 0 | return NULL; |
322 | 0 | } |
323 | | |
324 | 0 | p = _gpgrt_realloc (NULL, bytes); |
325 | 0 | if (p) |
326 | 0 | memset (p, 0, bytes); |
327 | 0 | return p; |
328 | 0 | } |
329 | | |
330 | | |
331 | | char * |
332 | | _gpgrt_strdup (const char *string) |
333 | 0 | { |
334 | 0 | size_t len = strlen (string); |
335 | 0 | char *p; |
336 | |
|
337 | 0 | p = _gpgrt_realloc (NULL, len + 1); |
338 | 0 | if (p) |
339 | 0 | strcpy (p, string); |
340 | 0 | return p; |
341 | 0 | } |
342 | | |
343 | | |
344 | | /* Helper for _gpgrt_strconcat and gpgrt_strconcat. */ |
345 | | char * |
346 | | _gpgrt_strconcat_core (const char *s1, va_list arg_ptr) |
347 | 0 | { |
348 | 0 | const char *argv[48]; |
349 | 0 | size_t argc; |
350 | 0 | size_t needed; |
351 | 0 | char *buffer, *p; |
352 | |
|
353 | 0 | argc = 0; |
354 | 0 | argv[argc++] = s1; |
355 | 0 | needed = strlen (s1); |
356 | 0 | while (((argv[argc] = va_arg (arg_ptr, const char *)))) |
357 | 0 | { |
358 | 0 | needed += strlen (argv[argc]); |
359 | 0 | if (argc >= DIM (argv)-1) |
360 | 0 | { |
361 | 0 | _gpg_err_set_errno (EINVAL); |
362 | 0 | return NULL; |
363 | 0 | } |
364 | 0 | argc++; |
365 | 0 | } |
366 | 0 | needed++; |
367 | 0 | buffer = _gpgrt_malloc (needed); |
368 | 0 | if (buffer) |
369 | 0 | { |
370 | 0 | for (p = buffer, argc=0; argv[argc]; argc++) |
371 | 0 | p = stpcpy (p, argv[argc]); |
372 | 0 | } |
373 | 0 | return buffer; |
374 | 0 | } |
375 | | |
376 | | |
377 | | char * |
378 | | _gpgrt_strconcat (const char *s1, ...) |
379 | 0 | { |
380 | 0 | va_list arg_ptr; |
381 | 0 | char *result; |
382 | |
|
383 | 0 | if (!s1) |
384 | 0 | result = _gpgrt_strdup (""); |
385 | 0 | else |
386 | 0 | { |
387 | 0 | va_start (arg_ptr, s1); |
388 | 0 | result = _gpgrt_strconcat_core (s1, arg_ptr); |
389 | 0 | va_end (arg_ptr); |
390 | 0 | } |
391 | 0 | return result; |
392 | 0 | } |
393 | | |
394 | | |
395 | | /* The free to be used for data returned by the public API. */ |
396 | | void |
397 | | _gpgrt_free (void *a) |
398 | 351k | { |
399 | 351k | int save_errno; |
400 | | |
401 | 351k | if (!a) |
402 | 4.74k | return; /* Shortcut */ |
403 | | |
404 | | /* In case ERRNO is set we better save it so that the free machinery |
405 | | * may not accidentally change ERRNO. We restore it only if it was |
406 | | * already set to comply with the usual C semantic for ERRNO. |
407 | | * See also https://dev.gnupg.org/T5393#146261 */ |
408 | 346k | save_errno = errno; |
409 | 346k | _gpgrt_realloc (a, 0); |
410 | 346k | if (save_errno && save_errno != errno) |
411 | 0 | _gpg_err_set_errno (save_errno); |
412 | 346k | } |
413 | | |
414 | | |
415 | | void |
416 | | _gpg_err_set_errno (int err) |
417 | 50.4k | { |
418 | 50.4k | errno = err; |
419 | 50.4k | } |
420 | | |
421 | | |
422 | | |
423 | | /* Internal tracing functions. Except for TRACE_FP we use flockfile |
424 | | * and funlockfile to protect their use. |
425 | | * |
426 | | * Warning: Take care with the trace functions - they may not use any |
427 | | * of our services, in particular not the syscall clamp mechanism for |
428 | | * reasons explained in w32-stream.c:create_reader. */ |
429 | | static FILE *trace_fp; |
430 | | static int trace_save_errno; |
431 | | static int trace_with_errno; |
432 | | static const char *trace_arg_module; |
433 | | static const char *trace_arg_file; |
434 | | static int trace_arg_line; |
435 | | static int trace_missing_lf; |
436 | | static int trace_prefix_done; |
437 | | |
438 | | void |
439 | | _gpgrt_internal_trace_begin (const char *module, const char *file, int line, |
440 | | int with_errno) |
441 | 0 | { |
442 | 0 | int save_errno = errno; |
443 | |
|
444 | 0 | if (!trace_fp) |
445 | 0 | { |
446 | 0 | FILE *fp; |
447 | 0 | const char *s = getenv ("GPGRT_TRACE_FILE"); |
448 | |
|
449 | 0 | if (!s || !(fp = fopen (s, "wb"))) |
450 | 0 | fp = stderr; |
451 | 0 | trace_fp = fp; |
452 | 0 | } |
453 | |
|
454 | 0 | #ifdef HAVE_FLOCKFILE |
455 | 0 | flockfile (trace_fp); |
456 | 0 | #endif |
457 | 0 | trace_save_errno = save_errno; |
458 | 0 | trace_with_errno = with_errno; |
459 | 0 | trace_arg_module = module; |
460 | 0 | trace_arg_file = file; |
461 | 0 | trace_arg_line = line; |
462 | 0 | trace_missing_lf = 0; |
463 | 0 | trace_prefix_done = 0; |
464 | 0 | } |
465 | | |
466 | | static void |
467 | | print_internal_trace_prefix (void) |
468 | 0 | { |
469 | 0 | if (!trace_prefix_done) |
470 | 0 | { |
471 | 0 | trace_prefix_done = 1; |
472 | 0 | fprintf (trace_fp, "%s:%s:%d: ", |
473 | 0 | trace_arg_module,/* npth_is_protected ()?"":"^",*/ |
474 | 0 | trace_arg_file, trace_arg_line); |
475 | 0 | } |
476 | 0 | } |
477 | | |
478 | | static void |
479 | | do_internal_trace (const char *format, va_list arg_ptr) |
480 | 0 | { |
481 | 0 | print_internal_trace_prefix (); |
482 | 0 | vfprintf (trace_fp, format, arg_ptr); |
483 | 0 | if (trace_with_errno) |
484 | 0 | fprintf (trace_fp, " errno=%s", strerror (trace_save_errno)); |
485 | 0 | if (*format && format[strlen(format)-1] != '\n') |
486 | 0 | fputc ('\n', trace_fp); |
487 | 0 | } |
488 | | |
489 | | void |
490 | | _gpgrt_internal_trace_printf (const char *format, ...) |
491 | 0 | { |
492 | 0 | va_list arg_ptr; |
493 | |
|
494 | 0 | print_internal_trace_prefix (); |
495 | 0 | va_start (arg_ptr, format) ; |
496 | 0 | vfprintf (trace_fp, format, arg_ptr); |
497 | 0 | va_end (arg_ptr); |
498 | 0 | trace_missing_lf = (*format && format[strlen(format)-1] != '\n'); |
499 | 0 | } |
500 | | |
501 | | |
502 | | void |
503 | | _gpgrt_internal_trace (const char *format, ...) |
504 | 0 | { |
505 | 0 | va_list arg_ptr; |
506 | |
|
507 | 0 | va_start (arg_ptr, format) ; |
508 | 0 | do_internal_trace (format, arg_ptr); |
509 | 0 | va_end (arg_ptr); |
510 | 0 | } |
511 | | |
512 | | |
513 | | void |
514 | | _gpgrt_internal_trace_end (void) |
515 | 0 | { |
516 | 0 | int save_errno = trace_save_errno; |
517 | |
|
518 | 0 | if (trace_missing_lf) |
519 | 0 | fputc ('\n', trace_fp); |
520 | 0 | #ifdef HAVE_FLOCKFILE |
521 | 0 | funlockfile (trace_fp); |
522 | 0 | #endif |
523 | 0 | errno = save_errno; |
524 | 0 | } |
525 | | |
526 | | |
527 | | |
528 | | #ifdef HAVE_W32_SYSTEM |
529 | | /***************************************** |
530 | | ******** Below is only Windows code. **** |
531 | | *****************************************/ |
532 | | |
533 | | static char * |
534 | | get_locale_dir (void) |
535 | | { |
536 | | static wchar_t moddir[MAX_PATH+5]; |
537 | | char *result, *p; |
538 | | int nbytes; |
539 | | |
540 | | if (!GetModuleFileNameW (NULL, moddir, MAX_PATH)) |
541 | | *moddir = 0; |
542 | | |
543 | | #define SLDIR "\\share\\locale" |
544 | | if (*moddir) |
545 | | { |
546 | | nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL); |
547 | | if (nbytes < 0) |
548 | | return NULL; |
549 | | |
550 | | result = malloc (nbytes + strlen (SLDIR) + 1); |
551 | | if (result) |
552 | | { |
553 | | nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, |
554 | | result, nbytes, NULL, NULL); |
555 | | if (nbytes < 0) |
556 | | { |
557 | | free (result); |
558 | | result = NULL; |
559 | | } |
560 | | else |
561 | | { |
562 | | p = strrchr (result, '\\'); |
563 | | if (p) |
564 | | *p = 0; |
565 | | /* If we are installed below "bin" strip that part and |
566 | | use the top directory instead. |
567 | | |
568 | | Background: Under Windows we don't install GnuPG |
569 | | below bin/ but in the top directory with only share/, |
570 | | lib/, and etc/ below it. One of the reasons is to |
571 | | keep the the length of the filenames at bay so not to |
572 | | increase the limited length of the PATH envvar. |
573 | | Another and more important reason, however, is that |
574 | | the very first GPG versions on W32 were installed |
575 | | into a flat directory structure and for best |
576 | | compatibility with these versions we didn't changed |
577 | | that later. For WindowsCE we can right away install |
578 | | it under bin, though. The hack with detection of the |
579 | | bin directory part allows us to eventually migrate to |
580 | | such a directory layout under plain Windows without |
581 | | the need to change libgpg-error. */ |
582 | | p = strrchr (result, '\\'); |
583 | | if (p && !strcmp (p+1, "bin")) |
584 | | *p = 0; |
585 | | /* Append the static part. */ |
586 | | strcat (result, SLDIR); |
587 | | } |
588 | | } |
589 | | } |
590 | | else /* Use the old default value. */ |
591 | | { |
592 | | result = malloc (10 + strlen (SLDIR) + 1); |
593 | | if (result) |
594 | | { |
595 | | strcpy (result, "c:\\gnupg"); |
596 | | strcat (result, SLDIR); |
597 | | } |
598 | | } |
599 | | #undef SLDIR |
600 | | return result; |
601 | | } |
602 | | |
603 | | |
604 | | static void |
605 | | drop_locale_dir (char *locale_dir) |
606 | | { |
607 | | free (locale_dir); |
608 | | } |
609 | | |
610 | | |
611 | | /* Return the tls object. This function is guaranteed to return a |
612 | | valid non-NULL object. */ |
613 | | struct tls_space_s * |
614 | | get_tls (void) |
615 | | { |
616 | | struct tls_space_s *tls; |
617 | | |
618 | | tls = TlsGetValue (tls_index); |
619 | | if (!tls) |
620 | | { |
621 | | /* Called by a thread which existed before this DLL was loaded. |
622 | | Allocate the space. */ |
623 | | tls = LocalAlloc (LPTR, sizeof *tls); |
624 | | if (!tls) |
625 | | { |
626 | | /* No way to continue - commit suicide. */ |
627 | | _gpgrt_abort (); |
628 | | } |
629 | | tls->gt_use_utf8 = 0; |
630 | | TlsSetValue (tls_index, tls); |
631 | | } |
632 | | |
633 | | return tls; |
634 | | } |
635 | | |
636 | | |
637 | | /* Entry point called by the DLL loader. */ |
638 | | #ifdef DLL_EXPORT |
639 | | int WINAPI |
640 | | DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved) |
641 | | { |
642 | | struct tls_space_s *tls; |
643 | | (void)reserved; |
644 | | (void)hinst; |
645 | | |
646 | | switch (reason) |
647 | | { |
648 | | case DLL_PROCESS_ATTACH: |
649 | | tls_index = TlsAlloc (); |
650 | | if (tls_index == TLS_OUT_OF_INDEXES) |
651 | | return FALSE; |
652 | | #ifndef _GPG_ERR_HAVE_CONSTRUCTOR |
653 | | /* If we have not constructors (e.g. MSC) we call it here. */ |
654 | | _gpg_w32__init_gettext_module (); |
655 | | #endif |
656 | | /* fallthru. */ |
657 | | case DLL_THREAD_ATTACH: |
658 | | tls = LocalAlloc (LPTR, sizeof *tls); |
659 | | if (!tls) |
660 | | return FALSE; |
661 | | tls->gt_use_utf8 = 0; |
662 | | TlsSetValue (tls_index, tls); |
663 | | if (reason == DLL_PROCESS_ATTACH) |
664 | | { |
665 | | real_init (); |
666 | | } |
667 | | break; |
668 | | |
669 | | case DLL_THREAD_DETACH: |
670 | | tls = TlsGetValue (tls_index); |
671 | | if (tls) |
672 | | LocalFree (tls); |
673 | | break; |
674 | | |
675 | | case DLL_PROCESS_DETACH: |
676 | | tls = TlsGetValue (tls_index); |
677 | | if (tls) |
678 | | LocalFree (tls); |
679 | | TlsFree (tls_index); |
680 | | break; |
681 | | |
682 | | default: |
683 | | break; |
684 | | } |
685 | | |
686 | | return TRUE; |
687 | | } |
688 | | #endif /*DLL_EXPORT*/ |
689 | | |
690 | | #endif /*HAVE_W32_SYSTEM*/ |