• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/libgpg-error-1.10/src/
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 <http://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 <gpg-error.h>
30
31#include "gettext.h"
32#include "init.h"
33
34#ifdef HAVE_W32CE_SYSTEM
35# include "mkw32errmap.map.c"  /* Generated map_w32codes () */
36#endif
37
38
39/* Locale directory support.  */
40
41#if HAVE_W32_SYSTEM
42
43#include <windows.h>
44
45static int tls_index = TLS_OUT_OF_INDEXES;  /* Index for the TLS functions.  */
46
47static char *get_locale_dir (void);
48static void drop_locale_dir (char *locale_dir);
49
50#else /*!HAVE_W32_SYSTEM*/
51
52#define get_locale_dir() LOCALEDIR
53#define drop_locale_dir(dir)
54
55#endif /*!HAVE_W32_SYSTEM*/
56
57
58static void
59real_init (void)
60{
61#ifdef ENABLE_NLS
62  char *locale_dir;
63
64  /* We only have to bind our locale directory to our text domain.  */
65  locale_dir = get_locale_dir ();
66  if (locale_dir)
67    {
68      bindtextdomain (PACKAGE, locale_dir);
69      drop_locale_dir (locale_dir);
70    }
71#endif
72}
73
74/* Initialize the library.  This function should be run early.  */
75gpg_error_t
76gpg_err_init (void)
77{
78#ifdef HAVE_W32_SYSTEM
79# ifdef DLL_EXPORT
80  /* We always have a constructor and thus this function is called
81     automatically.  Due to the way the C init code of mingw works,
82     the constructors are called before our DllMain function is
83     called.  The problem with that is that the TLS has not been setup
84     and w32-gettext.c requires TLS.  To solve this we do nothing here
85     but call the actual init code from our DllMain.  */
86# else /*!DLL_EXPORT*/
87  /* Note that if the TLS is actually used, we can't release the TLS
88     as there is no way to know when a thread terminates (i.e. no
89     thread-specific-atexit).  You are really better off to use the
90     DLL! */
91  if (tls_index == TLS_OUT_OF_INDEXES)
92    {
93      tls_index = TlsAlloc ();
94      if (tls_index == TLS_OUT_OF_INDEXES)
95        {
96          /* No way to continue - commit suicide.  */
97          abort ();
98        }
99      _gpg_w32__init_gettext_module ();
100      real_init ();
101    }
102# endif /*!DLL_EXPORT*/
103#else
104  real_init ();
105#endif
106  return 0;
107}
108
109
110/* Deinitialize libgpg-error.  This function is only used in special
111   circumstances.  No gpg-error function should be used after this
112   function has been called.  A value of 0 passed for MODE
113   deinitializes the entire libgpg-error, a value of 1 releases
114   resources allocated for the current thread and only that thread may
115   not anymore access libgpg-error after such a call.  Under Windows
116   this function may be called from the DllMain function of a DLL
117   which statically links to libgpg-error.  */
118void
119gpg_err_deinit (int mode)
120{
121#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
122  struct tls_space_s *tls;
123
124  tls = TlsGetValue (tls_index);
125  if (tls)
126    {
127      TlsSetValue (tls_index, NULL);
128      LocalFree (tls);
129    }
130
131  if (mode == 0)
132    {
133      TlsFree (tls_index);
134      tls_index = TLS_OUT_OF_INDEXES;
135    }
136#else
137  (void)mode;
138#endif
139}
140
141
142
143#ifdef HAVE_W32_SYSTEM
144
145/* Return a malloced string encoded in UTF-8 from the wide char input
146   string STRING.  Caller must free this value.  Returns NULL on
147   failure.  Caller may use GetLastError to get the actual error
148   number.  The result of calling this function with STRING set to
149   NULL is not defined.  */
150static char *
151wchar_to_utf8 (const wchar_t *string)
152{
153  int n;
154  char *result;
155
156  /* Note, that CP_UTF8 is not defined in Windows versions earlier
157     than NT.  */
158  n = WideCharToMultiByte (CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
159  if (n < 0)
160    return NULL;
161
162  result = malloc (n+1);
163  if (result)
164    {
165      n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL);
166      if (n < 0)
167        {
168          free (result);
169          result = NULL;
170        }
171    }
172  return result;
173}
174
175
176/* Return a malloced wide char string from an UTF-8 encoded input
177   string STRING.  Caller must free this value.  Returns NULL on
178   failure.  Caller may use GetLastError to get the actual error
179   number.  The result of calling this function with STRING set to
180   NULL is not defined.  */
181static wchar_t *
182utf8_to_wchar (const char *string)
183{
184  int n;
185  wchar_t *result;
186
187  n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0);
188  if (n < 0)
189    return NULL;
190
191  result = malloc ((n+1) * sizeof *result);
192  if (result)
193    {
194      n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n);
195      if (n < 0)
196        {
197          free (result);
198          result = NULL;
199        }
200      return NULL;
201    }
202  return result;
203}
204
205
206static char *
207get_locale_dir (void)
208{
209  static wchar_t moddir[MAX_PATH+5];
210  char *result, *p;
211  int nbytes;
212
213  if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
214    *moddir = 0;
215
216#define SLDIR "\\share\\locale"
217  if (*moddir)
218    {
219      nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
220      if (nbytes < 0)
221        return NULL;
222
223      result = malloc (nbytes + strlen (SLDIR) + 1);
224      if (result)
225        {
226          nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
227                                        result, nbytes, NULL, NULL);
228          if (nbytes < 0)
229            {
230              free (result);
231              result = NULL;
232            }
233          else
234            {
235              p = strrchr (result, '\\');
236              if (p)
237                *p = 0;
238              /* If we are installed below "bin" strip that part and
239                 use the top directory instead.
240
241                 Background: Under Windows we don't install GnuPG
242                 below bin/ but in the top directory with only share/,
243                 lib/, and etc/ below it.  One of the reasons is to
244                 keep the the length of the filenames at bay so not to
245                 increase the limited length of the PATH envvar.
246                 Another and more important reason, however, is that
247                 the very first GPG versions on W32 were installed
248                 into a flat directory structure and for best
249                 compatibility with these versions we didn't changed
250                 that later.  For WindowsCE we can right away install
251                 it under bin, though.  The hack with detection of the
252                 bin directory part allows us to eventually migrate to
253                 such a directory layout under plain Windows without
254                 the need to change libgpg-error.  */
255              p = strrchr (result, '\\');
256              if (p && !strcmp (p+1, "bin"))
257                *p = 0;
258              /* Append the static part.  */
259              strcat (result, SLDIR);
260            }
261        }
262    }
263  else /* Use the old default value.  */
264    {
265      result = malloc (10 + strlen (SLDIR) + 1);
266      if (result)
267        {
268          strcpy (result, "c:\\gnupg");
269          strcat (result, SLDIR);
270        }
271    }
272#undef SLDIR
273  return result;
274}
275
276
277static void
278drop_locale_dir (char *locale_dir)
279{
280  free (locale_dir);
281}
282
283
284/* Return the tls object.  This function is guaranteed to return a
285   valid non-NULL object.  */
286struct tls_space_s *
287get_tls (void)
288{
289  struct tls_space_s *tls;
290
291  tls = TlsGetValue (tls_index);
292  if (!tls)
293    {
294      /* Called by a thread which existed before this DLL was loaded.
295         Allocate the space.  */
296      tls = LocalAlloc (LPTR, sizeof *tls);
297      if (!tls)
298        {
299          /* No way to continue - commit suicide.  */
300          abort ();
301        }
302      tls->gt_use_utf8 = 0;
303      TlsSetValue (tls_index, tls);
304    }
305
306  return tls;
307}
308
309
310/* Return the value of the ERRNO variable.  This needs to be a
311   function so that we can have a per-thread ERRNO.  This is used only
312   on WindowsCE because that OS misses an errno.   */
313#ifdef HAVE_W32CE_SYSTEM
314int
315_gpg_w32ce_get_errno (void)
316{
317  return map_w32codes ( GetLastError () );
318}
319#endif /*HAVE_W32CE_SYSTEM*/
320
321
322/* Replacement strerror function for WindowsCE.  */
323#ifdef HAVE_W32CE_SYSTEM
324char *
325_gpg_w32ce_strerror (int err)
326{
327  struct tls_space_s *tls = get_tls ();
328  wchar_t tmpbuf[STRBUFFER_SIZE];
329  int n;
330
331  if (err == -1)
332    err = _gpg_w32ce_get_errno ();
333
334  /* Note: On a German HTC Touch Pro2 device I also tried
335     LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned
336     English messages.  */
337  if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
338                      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
339                      tmpbuf, STRBUFFER_SIZE -1,
340                      NULL))
341    {
342      n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
343                               tls->strerror_buffer,
344                               sizeof tls->strerror_buffer -1,
345                               NULL, NULL);
346    }
347  else
348    n = -1;
349
350  if (n < 0)
351    snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
352              "[w32err=%d]", err);
353  return tls->strerror_buffer;
354}
355#endif /*HAVE_W32CE_SYSTEM*/
356
357
358void
359gpg_err_set_errno (int err)
360{
361#ifdef HAVE_W32CE_SYSTEM
362  SetLastError (err);
363#else /*!HAVE_W32CE_SYSTEM*/
364  errno = err;
365#endif /*!HAVE_W32CE_SYSTEM*/
366}
367
368
369/* Entry point called by the DLL loader.  */
370#ifdef DLL_EXPORT
371int WINAPI
372DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
373{
374  struct tls_space_s *tls;
375  (void)reserved;
376
377  switch (reason)
378    {
379    case DLL_PROCESS_ATTACH:
380      tls_index = TlsAlloc ();
381      if (tls_index == TLS_OUT_OF_INDEXES)
382        return FALSE;
383      /* falltru.  */
384    case DLL_THREAD_ATTACH:
385      tls = LocalAlloc (LPTR, sizeof *tls);
386      if (!tls)
387        return FALSE;
388      tls->gt_use_utf8 = 0;
389      TlsSetValue (tls_index, tls);
390      if (reason == DLL_PROCESS_ATTACH)
391        {
392          real_init ();
393        }
394      break;
395
396    case DLL_THREAD_DETACH:
397      tls = TlsGetValue (tls_index);
398      if (tls)
399        LocalFree (tls);
400      break;
401
402    case DLL_PROCESS_DETACH:
403      tls = TlsGetValue (tls_index);
404      if (tls)
405        LocalFree (tls);
406      TlsFree (tls_index);
407      break;
408
409    default:
410      break;
411    }
412
413  return TRUE;
414}
415#endif /*DLL_EXPORT*/
416
417#else /*!HAVE_W32_SYSTEM*/
418
419void
420gpg_err_set_errno (int err)
421{
422  errno = err;
423}
424
425#endif /*!HAVE_W32_SYSTEM*/
426