18f69dc3cab90e2628e1f43a8d91d5a21281322c
[platform/upstream/dbus.git] / dbus / dbus-sysdeps.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation)
3  * 
4  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
5  * Copyright (C) 2003 CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #include <config.h>
26 #include "dbus-internals.h"
27 #include "dbus-sysdeps.h"
28 #include "dbus-threads.h"
29 #include "dbus-protocol.h"
30 #include "dbus-string.h"
31 #include "dbus-list.h"
32
33 /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
34  * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
35  *
36  * These are the standard ANSI C headers...
37  */
38 #if HAVE_LOCALE_H
39 #include <locale.h>
40 #endif
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdio.h>
44
45 #ifdef HAVE_ERRNO_H
46 #include <errno.h>
47 #endif
48
49 _DBUS_DEFINE_GLOBAL_LOCK (win_fds);
50 _DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache);
51 _DBUS_DEFINE_GLOBAL_LOCK (system_users);
52
53 #ifdef DBUS_WIN
54   #include <stdlib.h>
55 #elif (defined __APPLE__)
56 # include <crt_externs.h>
57 # define environ (*_NSGetEnviron())
58 #else
59 extern char **environ;
60 #endif
61
62 /**
63  * @defgroup DBusSysdeps Internal system-dependent API
64  * @ingroup DBusInternals
65  * @brief Internal system-dependent API available on UNIX and Windows
66  *
67  * The system-dependent API has a dual purpose. First, it encapsulates
68  * all usage of operating system APIs for ease of auditing and to
69  * avoid cluttering the rest of the code with bizarre OS quirks and
70  * headers. Second, it abstracts different operating system APIs for
71  * portability.
72  * 
73  * @{
74  */
75
76 /**
77  * Aborts the program with SIGABRT (dumping core).
78  */
79 void
80 _dbus_abort (void)
81 {
82   const char *s;
83   
84   _dbus_print_backtrace ();
85   
86   s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
87   if (s && *s)
88     {
89       /* don't use _dbus_warn here since it can _dbus_abort() */
90       fprintf (stderr, "  Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ());
91       _dbus_sleep_milliseconds (1000 * 180);
92     }
93   
94   abort ();
95   _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
96 }
97
98 /**
99  * Wrapper for setenv(). If the value is #NULL, unsets
100  * the environment variable.
101  *
102  * There is an unfixable memleak in that it is unsafe to
103  * free memory malloced for use with setenv. This is because
104  * we can not rely on internal implementation details of
105  * the underlying libc library.
106  *
107  * @param varname name of environment variable
108  * @param value value of environment variable
109  * @returns #TRUE on success.
110  */
111 dbus_bool_t
112 _dbus_setenv (const char *varname,
113               const char *value)
114 {
115   _dbus_assert (varname != NULL);
116   
117   if (value == NULL)
118     {
119 #ifdef HAVE_UNSETENV
120       unsetenv (varname);
121       return TRUE;
122 #else
123       char *putenv_value;
124       size_t len;
125
126       len = strlen (varname);
127
128       /* Use system malloc to avoid memleaks that dbus_malloc
129        * will get upset about.
130        */
131       
132       putenv_value = malloc (len + 2);
133       if (putenv_value == NULL)
134         return FALSE;
135
136       strcpy (putenv_value, varname);
137 #if defined(DBUS_WIN)
138       strcat (putenv_value, "=");
139 #endif
140       
141       return (putenv (putenv_value) == 0);
142 #endif
143     }
144   else
145     {
146 #ifdef HAVE_SETENV
147       return (setenv (varname, value, TRUE) == 0);
148 #else
149       char *putenv_value;
150       size_t len;
151       size_t varname_len;
152       size_t value_len;
153
154       varname_len = strlen (varname);
155       value_len = strlen (value);
156       
157       len = varname_len + value_len + 1 /* '=' */ ;
158
159       /* Use system malloc to avoid memleaks that dbus_malloc
160        * will get upset about.
161        */
162       
163       putenv_value = malloc (len + 1);
164       if (putenv_value == NULL)
165         return FALSE;
166
167       strcpy (putenv_value, varname);
168       strcpy (putenv_value + varname_len, "=");
169       strcpy (putenv_value + varname_len + 1, value);
170       
171       return (putenv (putenv_value) == 0);
172 #endif
173     }
174 }
175
176 /**
177  * Wrapper for getenv().
178  *
179  * @param varname name of environment variable
180  * @returns value of environment variable or #NULL if unset
181  */
182 const char*
183 _dbus_getenv (const char *varname)
184 {  
185   return getenv (varname);
186 }
187
188 /**
189  * Wrapper for clearenv().
190  *
191  * @returns #TRUE on success.
192  */
193 dbus_bool_t
194 _dbus_clearenv (void)
195 {
196   dbus_bool_t rc = TRUE;
197
198 #ifdef HAVE_CLEARENV
199   if (clearenv () != 0)
200      rc = FALSE;
201 #else
202
203   if (environ != NULL)
204     environ[0] = NULL;
205 #endif
206
207   return rc;
208 }
209
210 /**
211  * Gets a #NULL-terminated list of key=value pairs from the
212  * environment. Use dbus_free_string_array to free it.
213  *
214  * @returns the environment or #NULL on OOM
215  */
216 char **
217 _dbus_get_environment (void)
218 {
219   int i, length;
220   char **environment;
221
222   _dbus_assert (environ != NULL);
223
224   for (length = 0; environ[length] != NULL; length++);
225
226   /* Add one for NULL */
227   length++;
228
229   environment = dbus_new0 (char *, length);
230
231   if (environment == NULL)
232     return NULL;
233
234   for (i = 0; environ[i] != NULL; i++)
235     {
236       environment[i] = _dbus_strdup (environ[i]);
237
238       if (environment[i] == NULL)
239         break;
240     }
241
242   if (environ[i] != NULL)
243     {
244       dbus_free_string_array (environment);
245       environment = NULL;
246     }
247
248   return environment;
249 }
250
251 /**
252  * Split paths into a list of char strings
253  * 
254  * @param dirs string with pathes 
255  * @param suffix string concated to each path in dirs
256  * @param dir_list contains a list of splitted pathes
257  * return #TRUE is pathes could be splittes,#FALSE in oom case 
258  */
259 dbus_bool_t
260 _dbus_split_paths_and_append (DBusString *dirs, 
261                               const char *suffix, 
262                               DBusList  **dir_list)
263 {
264    int start;
265    int i;
266    int len;
267    char *cpath;
268    DBusString file_suffix;
269
270    start = 0;
271    i = 0;
272
273    _dbus_string_init_const (&file_suffix, suffix);
274
275    len = _dbus_string_get_length (dirs);
276
277    while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
278      {
279        DBusString path;
280
281        if (!_dbus_string_init (&path))
282           goto oom;
283
284        if (!_dbus_string_copy_len (dirs,
285                                    start,
286                                    i - start,
287                                    &path,
288                                    0))
289           {
290             _dbus_string_free (&path);
291             goto oom;
292           }
293
294         _dbus_string_chop_white (&path);
295
296         /* check for an empty path */
297         if (_dbus_string_get_length (&path) == 0)
298           goto next;
299
300         if (!_dbus_concat_dir_and_file (&path,
301                                         &file_suffix))
302           {
303             _dbus_string_free (&path);
304             goto oom;
305           }
306
307         if (!_dbus_string_copy_data(&path, &cpath))
308           {
309             _dbus_string_free (&path);
310             goto oom;
311           }
312
313         if (!_dbus_list_append (dir_list, cpath))
314           {
315             _dbus_string_free (&path);              
316             dbus_free (cpath);
317             goto oom;
318           }
319
320        next:
321         _dbus_string_free (&path);
322         start = i + 1;
323     } 
324       
325   if (start != len)
326     { 
327       DBusString path;
328
329       if (!_dbus_string_init (&path))
330         goto oom;
331
332       if (!_dbus_string_copy_len (dirs,
333                                   start,
334                                   len - start,
335                                   &path,
336                                   0))
337         {
338           _dbus_string_free (&path);
339           goto oom;
340         }
341
342       if (!_dbus_concat_dir_and_file (&path,
343                                       &file_suffix))
344         {
345           _dbus_string_free (&path);
346           goto oom;
347         }
348
349       if (!_dbus_string_copy_data(&path, &cpath))
350         {
351           _dbus_string_free (&path);
352           goto oom;
353         }
354
355       if (!_dbus_list_append (dir_list, cpath))
356         {
357           _dbus_string_free (&path);              
358           dbus_free (cpath);
359           goto oom;
360         }
361
362       _dbus_string_free (&path); 
363     }
364
365   return TRUE;
366
367  oom:
368   _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); 
369   _dbus_list_clear (dir_list);
370   return FALSE;
371 }
372
373 /** @} */
374
375 /**
376  * @addtogroup DBusString
377  *
378  * @{
379  */
380 /**
381  * Appends an integer to a DBusString.
382  * 
383  * @param str the string
384  * @param value the integer value
385  * @returns #FALSE if not enough memory or other failure.
386  */
387 dbus_bool_t
388 _dbus_string_append_int (DBusString *str,
389                          long        value)
390 {
391   /* this calculation is from comp.lang.c faq */
392 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
393   int orig_len;
394   int i;
395   char *buf;
396   
397   orig_len = _dbus_string_get_length (str);
398
399   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
400     return FALSE;
401
402   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
403
404   snprintf (buf, MAX_LONG_LEN, "%ld", value);
405
406   i = 0;
407   while (*buf)
408     {
409       ++buf;
410       ++i;
411     }
412   
413   _dbus_string_shorten (str, MAX_LONG_LEN - i);
414   
415   return TRUE;
416 }
417
418 /**
419  * Appends an unsigned integer to a DBusString.
420  * 
421  * @param str the string
422  * @param value the integer value
423  * @returns #FALSE if not enough memory or other failure.
424  */
425 dbus_bool_t
426 _dbus_string_append_uint (DBusString    *str,
427                           unsigned long  value)
428 {
429   /* this is wrong, but definitely on the high side. */
430 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
431   int orig_len;
432   int i;
433   char *buf;
434   
435   orig_len = _dbus_string_get_length (str);
436
437   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
438     return FALSE;
439
440   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
441
442   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
443
444   i = 0;
445   while (*buf)
446     {
447       ++buf;
448       ++i;
449     }
450   
451   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
452   
453   return TRUE;
454 }
455
456 #ifdef DBUS_BUILD_TESTS
457 /**
458  * Appends a double to a DBusString.
459  * 
460  * @param str the string
461  * @param value the floating point value
462  * @returns #FALSE if not enough memory or other failure.
463  */
464 dbus_bool_t
465 _dbus_string_append_double (DBusString *str,
466                             double      value)
467 {
468 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
469   int orig_len;
470   char *buf;
471   int i;
472   
473   orig_len = _dbus_string_get_length (str);
474
475   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
476     return FALSE;
477
478   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
479
480   snprintf (buf, MAX_LONG_LEN, "%g", value);
481
482   i = 0;
483   while (*buf)
484     {
485       ++buf;
486       ++i;
487     }
488   
489   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
490   
491   return TRUE;
492 }
493 #endif /* DBUS_BUILD_TESTS */
494
495 /**
496  * Parses an integer contained in a DBusString. Either return parameter
497  * may be #NULL if you aren't interested in it. The integer is parsed
498  * and stored in value_return. Return parameters are not initialized
499  * if the function returns #FALSE.
500  *
501  * @param str the string
502  * @param start the byte index of the start of the integer
503  * @param value_return return location of the integer value or #NULL
504  * @param end_return return location of the end of the integer, or #NULL
505  * @returns #TRUE on success
506  */
507 dbus_bool_t
508 _dbus_string_parse_int (const DBusString *str,
509                         int               start,
510                         long             *value_return,
511                         int              *end_return)
512 {
513   long v;
514   const char *p;
515   char *end;
516
517   p = _dbus_string_get_const_data_len (str, start,
518                                        _dbus_string_get_length (str) - start);
519
520   end = NULL;
521   _dbus_set_errno_to_zero ();
522   v = strtol (p, &end, 0);
523   if (end == NULL || end == p || errno != 0)
524     return FALSE;
525
526   if (value_return)
527     *value_return = v;
528   if (end_return)
529     *end_return = start + (end - p);
530
531   return TRUE;
532 }
533
534 /**
535  * Parses an unsigned integer contained in a DBusString. Either return
536  * parameter may be #NULL if you aren't interested in it. The integer
537  * is parsed and stored in value_return. Return parameters are not
538  * initialized if the function returns #FALSE.
539  *
540  * @param str the string
541  * @param start the byte index of the start of the integer
542  * @param value_return return location of the integer value or #NULL
543  * @param end_return return location of the end of the integer, or #NULL
544  * @returns #TRUE on success
545  */
546 dbus_bool_t
547 _dbus_string_parse_uint (const DBusString *str,
548                          int               start,
549                          unsigned long    *value_return,
550                          int              *end_return)
551 {
552   unsigned long v;
553   const char *p;
554   char *end;
555
556   p = _dbus_string_get_const_data_len (str, start,
557                                        _dbus_string_get_length (str) - start);
558
559   end = NULL;
560   _dbus_set_errno_to_zero ();
561   v = strtoul (p, &end, 0);
562   if (end == NULL || end == p || errno != 0)
563     return FALSE;
564
565   if (value_return)
566     *value_return = v;
567   if (end_return)
568     *end_return = start + (end - p);
569
570   return TRUE;
571 }
572
573 #ifdef DBUS_BUILD_TESTS
574 static dbus_bool_t
575 ascii_isspace (char c)
576 {
577   return (c == ' ' ||
578           c == '\f' ||
579           c == '\n' ||
580           c == '\r' ||
581           c == '\t' ||
582           c == '\v');
583 }
584 #endif /* DBUS_BUILD_TESTS */
585
586 #ifdef DBUS_BUILD_TESTS
587 static dbus_bool_t
588 ascii_isdigit (char c)
589 {
590   return c >= '0' && c <= '9';
591 }
592 #endif /* DBUS_BUILD_TESTS */
593
594 #ifdef DBUS_BUILD_TESTS
595 static dbus_bool_t
596 ascii_isxdigit (char c)
597 {
598   return (ascii_isdigit (c) ||
599           (c >= 'a' && c <= 'f') ||
600           (c >= 'A' && c <= 'F'));
601 }
602 #endif /* DBUS_BUILD_TESTS */
603
604 #ifdef DBUS_BUILD_TESTS
605 /* Calls strtod in a locale-independent fashion, by looking at
606  * the locale data and patching the decimal comma to a point.
607  *
608  * Relicensed from glib.
609  */
610 static double
611 ascii_strtod (const char *nptr,
612               char      **endptr)
613 {
614   /* FIXME: The Win32 C library's strtod() doesn't handle hex.
615    * Presumably many Unixes don't either.
616    */
617
618   char *fail_pos;
619   double val;
620   struct lconv *locale_data;
621   const char *decimal_point;
622   int decimal_point_len;
623   const char *p, *decimal_point_pos;
624   const char *end = NULL; /* Silence gcc */
625
626   fail_pos = NULL;
627
628 #if HAVE_LOCALECONV
629   locale_data = localeconv ();
630   decimal_point = locale_data->decimal_point;
631 #else
632   decimal_point = ".";
633 #endif
634
635   decimal_point_len = strlen (decimal_point);
636   _dbus_assert (decimal_point_len != 0);
637   
638   decimal_point_pos = NULL;
639   if (decimal_point[0] != '.' ||
640       decimal_point[1] != 0)
641     {
642       p = nptr;
643       /* Skip leading space */
644       while (ascii_isspace (*p))
645         p++;
646       
647       /* Skip leading optional sign */
648       if (*p == '+' || *p == '-')
649         p++;
650       
651       if (p[0] == '0' &&
652           (p[1] == 'x' || p[1] == 'X'))
653         {
654           p += 2;
655           /* HEX - find the (optional) decimal point */
656           
657           while (ascii_isxdigit (*p))
658             p++;
659           
660           if (*p == '.')
661             {
662               decimal_point_pos = p++;
663               
664               while (ascii_isxdigit (*p))
665                 p++;
666               
667               if (*p == 'p' || *p == 'P')
668                 p++;
669               if (*p == '+' || *p == '-')
670                 p++;
671               while (ascii_isdigit (*p))
672                 p++;
673               end = p;
674             }
675         }
676       else
677         {
678           while (ascii_isdigit (*p))
679             p++;
680           
681           if (*p == '.')
682             {
683               decimal_point_pos = p++;
684               
685               while (ascii_isdigit (*p))
686                 p++;
687               
688               if (*p == 'e' || *p == 'E')
689                 p++;
690               if (*p == '+' || *p == '-')
691                 p++;
692               while (ascii_isdigit (*p))
693                 p++;
694               end = p;
695             }
696         }
697       /* For the other cases, we need not convert the decimal point */
698     }
699
700   /* Set errno to zero, so that we can distinguish zero results
701      and underflows */
702   _dbus_set_errno_to_zero ();
703   
704   if (decimal_point_pos)
705     {
706       char *copy, *c;
707
708       /* We need to convert the '.' to the locale specific decimal point */
709       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
710       
711       c = copy;
712       memcpy (c, nptr, decimal_point_pos - nptr);
713       c += decimal_point_pos - nptr;
714       memcpy (c, decimal_point, decimal_point_len);
715       c += decimal_point_len;
716       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
717       c += end - (decimal_point_pos + 1);
718       *c = 0;
719
720       val = strtod (copy, &fail_pos);
721
722       if (fail_pos)
723         {
724           if (fail_pos > decimal_point_pos)
725             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
726           else
727             fail_pos = (char *)nptr + (fail_pos - copy);
728         }
729       
730       dbus_free (copy);
731           
732     }
733   else
734     val = strtod (nptr, &fail_pos);
735
736   if (endptr)
737     *endptr = fail_pos;
738   
739   return val;
740 }
741 #endif /* DBUS_BUILD_TESTS */
742
743 #ifdef DBUS_BUILD_TESTS
744 /**
745  * Parses a floating point number contained in a DBusString. Either
746  * return parameter may be #NULL if you aren't interested in it. The
747  * integer is parsed and stored in value_return. Return parameters are
748  * not initialized if the function returns #FALSE.
749  *
750  * @param str the string
751  * @param start the byte index of the start of the float
752  * @param value_return return location of the float value or #NULL
753  * @param end_return return location of the end of the float, or #NULL
754  * @returns #TRUE on success
755  */
756 dbus_bool_t
757 _dbus_string_parse_double (const DBusString *str,
758                            int               start,
759                            double           *value_return,
760                            int              *end_return)
761 {
762   double v;
763   const char *p;
764   char *end;
765
766   p = _dbus_string_get_const_data_len (str, start,
767                                        _dbus_string_get_length (str) - start);
768
769   /* parsing hex works on linux but isn't portable, so intercept it
770    * here to get uniform behavior.
771    */
772   if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
773     return FALSE;
774   
775   end = NULL;
776   _dbus_set_errno_to_zero ();
777   v = ascii_strtod (p, &end);
778   if (end == NULL || end == p || errno != 0)
779     return FALSE;
780
781   if (value_return)
782     *value_return = v;
783   if (end_return)
784     *end_return = start + (end - p);
785
786   return TRUE;
787 }
788 #endif /* DBUS_BUILD_TESTS */
789
790 /** @} */ /* DBusString group */
791
792 /**
793  * @addtogroup DBusInternalsUtils
794  * @{
795  */
796
797 void
798 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
799                                           int   n_bytes)
800 {
801   long tv_usec;
802   int i;
803   
804   /* fall back to pseudorandom */
805   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
806                  n_bytes);
807   
808   _dbus_get_current_time (NULL, &tv_usec);
809   srand (tv_usec);
810   
811   i = 0;
812   while (i < n_bytes)
813     {
814       double r;
815       unsigned int b;
816           
817       r = rand ();
818       b = (r / (double) RAND_MAX) * 255.0;
819
820       buffer[i] = b;
821
822       ++i;
823     }
824 }
825
826 /**
827  * Fills n_bytes of the given buffer with random bytes.
828  *
829  * @param buffer an allocated buffer
830  * @param n_bytes the number of bytes in buffer to write to
831  */
832 void
833 _dbus_generate_random_bytes_buffer (char *buffer,
834                                     int   n_bytes)
835 {
836   DBusString str;
837
838   if (!_dbus_string_init (&str))
839     {
840       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
841       return;
842     }
843
844   if (!_dbus_generate_random_bytes (&str, n_bytes))
845     {
846       _dbus_string_free (&str);
847       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
848       return;
849     }
850
851   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
852
853   _dbus_string_free (&str);
854 }
855
856 /**
857  * Generates the given number of random bytes, where the bytes are
858  * chosen from the alphanumeric ASCII subset.
859  *
860  * @param str the string
861  * @param n_bytes the number of random ASCII bytes to append to string
862  * @returns #TRUE on success, #FALSE if no memory or other failure
863  */
864 dbus_bool_t
865 _dbus_generate_random_ascii (DBusString *str,
866                              int         n_bytes)
867 {
868   static const char letters[] =
869     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
870   int i;
871   int len;
872   
873   if (!_dbus_generate_random_bytes (str, n_bytes))
874     return FALSE;
875   
876   len = _dbus_string_get_length (str);
877   i = len - n_bytes;
878   while (i < len)
879     {
880       _dbus_string_set_byte (str, i,
881                              letters[_dbus_string_get_byte (str, i) %
882                                      (sizeof (letters) - 1)]);
883
884       ++i;
885     }
886
887   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
888                                              n_bytes));
889
890   return TRUE;
891 }
892
893 /**
894  * Converts a UNIX errno, or Windows errno or WinSock error value into
895  * a #DBusError name.
896  *
897  * @todo should cover more errnos, specifically those
898  * from open().
899  * 
900  * @param error_number the errno.
901  * @returns an error name
902  */
903 const char*
904 _dbus_error_from_errno (int error_number)
905 {
906   switch (error_number)
907     {
908     case 0:
909       return DBUS_ERROR_FAILED;
910       
911 #ifdef EPROTONOSUPPORT
912     case EPROTONOSUPPORT:
913       return DBUS_ERROR_NOT_SUPPORTED;
914 #endif
915 #ifdef WSAEPROTONOSUPPORT
916     case WSAEPROTONOSUPPORT:
917       return DBUS_ERROR_NOT_SUPPORTED;
918 #endif
919 #ifdef EAFNOSUPPORT
920     case EAFNOSUPPORT:
921       return DBUS_ERROR_NOT_SUPPORTED;
922 #endif
923 #ifdef WSAEAFNOSUPPORT
924     case WSAEAFNOSUPPORT:
925       return DBUS_ERROR_NOT_SUPPORTED;
926 #endif
927 #ifdef ENFILE
928     case ENFILE:
929       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
930 #endif
931 #ifdef EMFILE
932     case EMFILE:
933       return DBUS_ERROR_LIMITS_EXCEEDED;
934 #endif
935 #ifdef EACCES
936     case EACCES:
937       return DBUS_ERROR_ACCESS_DENIED;
938 #endif
939 #ifdef EPERM
940     case EPERM:
941       return DBUS_ERROR_ACCESS_DENIED;
942 #endif
943 #ifdef ENOBUFS
944     case ENOBUFS:
945       return DBUS_ERROR_NO_MEMORY;
946 #endif
947 #ifdef ENOMEM
948     case ENOMEM:
949       return DBUS_ERROR_NO_MEMORY;
950 #endif
951 #ifdef ECONNREFUSED
952     case ECONNREFUSED:
953       return DBUS_ERROR_NO_SERVER;
954 #endif
955 #ifdef WSAECONNREFUSED
956     case WSAECONNREFUSED:
957       return DBUS_ERROR_NO_SERVER;
958 #endif
959 #ifdef ETIMEDOUT
960     case ETIMEDOUT:
961       return DBUS_ERROR_TIMEOUT;
962 #endif
963 #ifdef WSAETIMEDOUT
964     case WSAETIMEDOUT:
965       return DBUS_ERROR_TIMEOUT;
966 #endif
967 #ifdef ENETUNREACH
968     case ENETUNREACH:
969       return DBUS_ERROR_NO_NETWORK;
970 #endif
971 #ifdef WSAENETUNREACH
972     case WSAENETUNREACH:
973       return DBUS_ERROR_NO_NETWORK;
974 #endif
975 #ifdef EADDRINUSE
976     case EADDRINUSE:
977       return DBUS_ERROR_ADDRESS_IN_USE;
978 #endif
979 #ifdef WSAEADDRINUSE
980     case WSAEADDRINUSE:
981       return DBUS_ERROR_ADDRESS_IN_USE;
982 #endif
983 #ifdef EEXIST
984     case EEXIST:
985       return DBUS_ERROR_FILE_EXISTS;
986 #endif
987 #ifdef ENOENT
988     case ENOENT:
989       return DBUS_ERROR_FILE_NOT_FOUND;
990 #endif
991     }
992
993   return DBUS_ERROR_FAILED;
994 }
995
996 /**
997  * Converts the current system errno value into a #DBusError name.
998  *
999  * @returns an error name
1000  */
1001 const char*
1002 _dbus_error_from_system_errno (void)
1003 {
1004   return _dbus_error_from_errno (errno);
1005 }
1006
1007 /**
1008  * Assign 0 to the global errno variable
1009  */
1010 void
1011 _dbus_set_errno_to_zero (void)
1012 {
1013 #ifdef DBUS_WINCE
1014   SetLastError (0);
1015 #else
1016   errno = 0;
1017 #endif
1018 }
1019
1020 /**
1021  * See if errno is set
1022  * @returns #TRUE if errno is not 0
1023  */
1024 dbus_bool_t
1025 _dbus_get_is_errno_nonzero (void)
1026 {
1027   return errno != 0;
1028 }
1029
1030 /**
1031  * See if errno is ENOMEM
1032  * @returns #TRUE if errno == ENOMEM
1033  */
1034 dbus_bool_t
1035 _dbus_get_is_errno_enomem (void)
1036 {
1037   return errno == ENOMEM;
1038 }
1039
1040 /**
1041  * See if errno is EINTR
1042  * @returns #TRUE if errno == EINTR
1043  */
1044 dbus_bool_t
1045 _dbus_get_is_errno_eintr (void)
1046 {
1047   return errno == EINTR;
1048 }
1049
1050 /**
1051  * See if errno is EPIPE
1052  * @returns #TRUE if errno == EPIPE
1053  */
1054 dbus_bool_t
1055 _dbus_get_is_errno_epipe (void)
1056 {
1057   return errno == EPIPE;
1058 }
1059
1060 /**
1061  * Get error message from errno
1062  * @returns _dbus_strerror(errno)
1063  */
1064 const char*
1065 _dbus_strerror_from_errno (void)
1066 {
1067   return _dbus_strerror (errno);
1068 }
1069
1070 /**
1071  * Atomically get the value of an integer. It may change at any time
1072  * thereafter, so this is mostly only useful for assertions.
1073  *
1074  * This function temporarily increases the atomic integer, so only
1075  * use it in contexts where that would be OK (such as refcounts).
1076  *
1077  * @param atomic pointer to the integer to increment
1078  * @returns the value at this moment
1079  */
1080 dbus_int32_t
1081 _dbus_atomic_get (DBusAtomic *atomic)
1082 {
1083   dbus_int32_t old_value;
1084
1085   /* On Windows we use InterlockedIncrement and InterlockedDecrement,
1086    * and there is no InterlockedGet, so we have to change the value.
1087    * Increasing it is less likely to have bad side-effects (for instance,
1088    * it's OK for refcounts). */
1089   old_value = _dbus_atomic_inc (atomic);
1090   _dbus_atomic_dec (atomic);
1091   return old_value;
1092 }
1093
1094 /** @} end of sysdeps */
1095
1096 /* tests in dbus-sysdeps-util.c */