* dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps-spawn-win.c, dbus/dbus-sysdeps-win.h...
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-win.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2002, 2003  Red Hat, Inc.
5  * Copyright (C) 2003 CodeFactory AB
6  * Copyright (C) 2005 Novell, Inc.
7  * Copyright (C) 2006 Ralf Habacker <ralf.habacker@freenet.de>
8  * Copyright (C) 2006 Peter Kümmel  <syntheticpp@gmx.net>
9  * Copyright (C) 2006 Christian Ehrlicher <ch.ehrlicher@gmx.de>
10  *
11  * Licensed under the Academic Free License version 2.1
12  * 
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  */
28
29 /* #define ENABLE_DBUSUSERINFO */
30
31 struct DBusCredentials{
32     int uid;
33     int gid;
34     int pid;
35 };
36
37 #undef open
38
39 #define STRSAFE_NO_DEPRECATE
40
41 #ifndef DBUS_WINCE
42 #define _WIN32_WINNT 0x0500
43 #endif
44
45 #include "dbus-internals.h"
46 #include "dbus-sysdeps.h"
47 #include "dbus-threads.h"
48 #include "dbus-protocol.h"
49 #include "dbus-string.h"
50 #include "dbus-sysdeps-win.h"
51 #include "dbus-protocol.h"
52 #include "dbus-hash.h"
53 #include "dbus-sockets-win.h"
54 #include "dbus-list.h"
55 #include "dbus-credentials.h"
56
57 #include <windows.h>
58 #include <fcntl.h>
59
60 #include <process.h>
61 #include <sys/stat.h>
62 #include <sys/types.h>
63
64 #ifndef O_BINARY
65 #define O_BINARY 0
66 #endif
67
68 #ifndef HAVE_SOCKLEN_T
69 #define socklen_t int
70 #endif
71
72 #ifdef ENABLE_DBUSSOCKET
73 _DBUS_DEFINE_GLOBAL_LOCK (win_fds);
74 #endif
75
76 #ifdef ENABLE_UID_TO_SID
77 _DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache);
78 #endif
79
80 #ifdef ENABLE_DBUSUSERINFO
81 typedef struct {
82     int uid;
83     char *username;
84     int n_group_ids;
85     dbus_gid_t *group_ids;
86     int primary_gid;
87     char *homedir;
88 } DBusUserInfo;
89 #endif
90
91 #ifdef ENABLE_DBUSSOCKET
92 static
93 void 
94 _dbus_lock_sockets()
95 {
96         _dbus_assert (win_fds!=0); 
97         _DBUS_LOCK   (win_fds);
98 }
99
100 static
101 void 
102 _dbus_unlock_sockets()
103 {
104         _dbus_assert (win_fds!=0); 
105         _DBUS_UNLOCK (win_fds);
106 }
107 #endif
108
109 #ifdef _DBUS_WIN_USE_RANDOMIZER
110 static int  win_encap_randomizer;
111 #endif
112
113 #ifdef ENABLE_UID_TO_SID
114 static DBusHashTable *sid_atom_cache = NULL;
115 #endif
116
117 static DBusString dbusdir;
118 static int working_dir_init = 0;
119
120 int _dbus_init_working_dir(char *s)
121 {
122   /* change working directory to one level above 
123      of dbus-daemon executable path.  
124      This allows the usage of relative path in 
125      config files or command line parameters */
126   DBusString daemon_path,bin_path;
127
128   if (!_dbus_string_init (&daemon_path))
129     return FALSE;
130   
131   if (!_dbus_string_init (&bin_path))
132     return FALSE;
133
134   if (!_dbus_string_init (&dbusdir))
135     return FALSE;
136   
137   _dbus_string_append(&daemon_path,s);
138   _dbus_string_get_dirname(&daemon_path,&bin_path);
139   _dbus_string_get_dirname(&bin_path,&dbusdir);
140   chdir(_dbus_string_get_const_data(&dbusdir));
141   _dbus_verbose ("Change working path to %s\n",_dbus_string_get_const_data (&dbusdir));
142   working_dir_init = 1;
143   return TRUE;
144 }
145
146 DBusString *_dbus_get_working_dir(void)
147 {
148   if (!working_dir_init) 
149     return NULL;
150         
151   _dbus_verbose ("retrieving working path %s\n",_dbus_string_get_const_data (&dbusdir));
152   return &dbusdir;
153 }
154
155 /**
156  * File interface
157  *
158  */
159 dbus_bool_t
160 _dbus_file_open (DBusFile   *file,
161                  const char *filename,
162                  int         oflag,
163                  int         pmode)
164 {
165   if (pmode!=-1)
166     file->FDATA = _open (filename, oflag, pmode);
167   else
168     file->FDATA = _open (filename, oflag);
169   if (file->FDATA >= 0)
170     return TRUE;
171   else
172     {
173       file->FDATA = -1;
174       return FALSE;
175     }
176 }
177
178 dbus_bool_t
179 _dbus_file_close (DBusFile  *file,
180                   DBusError *error)
181 {
182   const int fd = file->FDATA;
183
184   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
185
186   _dbus_assert (fd >= 0);
187
188   if (_close (fd) == -1)
189     {
190       dbus_set_error (error, _dbus_error_from_errno (errno),
191                       "Could not close fd %d: %s", fd,
192                       _dbus_strerror (errno));
193       return FALSE;
194     }
195
196   file->FDATA = -1;
197   _dbus_verbose ("closed C file descriptor %d:\n",fd);
198
199   return TRUE;
200 }
201
202 int
203 _dbus_file_read(DBusFile   *file,
204                 DBusString *buffer,
205                 int         count)
206 {
207   const int fd = file->FDATA;
208   int bytes_read;
209   int start;
210   char *data;
211   _dbus_assert (count >= 0);
212
213   start = _dbus_string_get_length (buffer);
214
215   if (!_dbus_string_lengthen (buffer, count))
216     {
217       errno = ENOMEM;
218       return -1;
219     }
220
221   data = _dbus_string_get_data_len (buffer, start, count);
222
223   _dbus_assert (fd >= 0);
224
225   _dbus_verbose ("read: count=%d fd=%d\n", count, fd);
226   bytes_read = read (fd, data, count);
227
228   if (bytes_read == -1)
229     _dbus_verbose ("read: failed: %s\n", _dbus_strerror (errno));
230   else
231     _dbus_verbose ("read: = %d\n", bytes_read);
232
233   if (bytes_read < 0)
234     {
235       /* put length back (note that this doesn't actually realloc anything) */
236       _dbus_string_set_length (buffer, start);
237       return -1;
238     }
239   else
240     {
241       /* put length back (doesn't actually realloc) */
242       _dbus_string_set_length (buffer, start + bytes_read);
243
244 #if 0
245
246       if (bytes_read > 0)
247         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
248 #endif
249
250       return bytes_read;
251     }
252 }
253
254 int
255 _dbus_file_write (DBusFile         *file,
256                   const DBusString *buffer,
257                   int               start,
258                   int               len)
259 {
260   const int fd = file->FDATA;
261   const char *data;
262   int bytes_written;
263
264   data = _dbus_string_get_const_data_len (buffer, start, len);
265
266   _dbus_assert (fd >= 0);
267
268   _dbus_verbose ("write: len=%d fd=%d\n", len, fd);
269   bytes_written = write (fd, data, len);
270
271   if (bytes_written == -1)
272     _dbus_verbose ("write: failed: %s\n", _dbus_strerror (errno));
273   else
274     _dbus_verbose ("write: = %d\n", bytes_written);
275
276 #if 0
277
278   if (bytes_written > 0)
279     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
280 #endif
281
282   return bytes_written;
283 }
284
285 dbus_bool_t
286 _dbus_is_valid_file (DBusFile* file)
287 {
288   return file->FDATA >= 0;
289 }
290
291 dbus_bool_t _dbus_fstat (DBusFile    *file,
292                          struct stat *sb)
293 {
294   return fstat(file->FDATA, sb) >= 0;
295 }
296
297 /**
298  * write data to a pipe.
299  *
300  * @param pipe the pipe instance
301  * @param buffer the buffer to write data from
302  * @param start the first byte in the buffer to write
303  * @param len the number of bytes to try to write
304  * @param error error return
305  * @returns the number of bytes written or -1 on error
306  */
307 int
308 _dbus_pipe_write (DBusPipe         *pipe,
309                   const DBusString *buffer,
310                   int               start,
311                   int               len,
312                   DBusError        *error)
313 {
314   int written;
315   DBusFile file;
316   file.FDATA = pipe->fd_or_handle;
317   written = _dbus_file_write (&file, buffer, start, len);
318   if (written < 0)
319     {
320       dbus_set_error (error, DBUS_ERROR_FAILED,
321                       "Writing to pipe: %s\n",
322                       _dbus_strerror (errno));
323     }
324   return written;
325 }
326
327 /**
328  * close a pipe.
329  *
330  * @param pipe the pipe instance
331  * @param error return location for an error
332  * @returns #FALSE if error is set
333  */
334 int
335 _dbus_pipe_close  (DBusPipe         *pipe,
336                    DBusError        *error)
337 {
338   DBusFile file;
339   file.FDATA = pipe->fd_or_handle;
340   if (_dbus_file_close (&file, error) < 0)
341     {
342       return -1;
343     }
344   else
345     {
346       _dbus_pipe_invalidate (pipe);
347       return 0;
348     }
349 }
350
351 #undef FDATA
352
353 /**
354  * Socket interface
355  *
356  */
357
358 #ifdef ENABLE_DBUSSOCKET
359 static DBusSocket *win_fds = NULL;
360 static int win_n_fds = 0; // is this the size? rename to win_fds_size? #
361
362
363 #if 0
364 #define TO_HANDLE(n)   ((n)^win32_encap_randomizer)
365 #define FROM_HANDLE(n) ((n)^win32_encap_randomizer)
366 #else
367 #define TO_HANDLE(n)   ((n)+0x10000000)
368 #define FROM_HANDLE(n) ((n)-0x10000000)
369 #define IS_HANDLE(n)   ((n)&0x10000000)
370 #endif
371
372
373 static
374 void
375 _dbus_win_deallocate_fd (int fd)
376 {
377   _DBUS_LOCK (win_fds);
378   win_fds[FROM_HANDLE (fd)].is_used = 0;
379   _DBUS_UNLOCK (win_fds);
380 }
381
382 static
383 int
384 _dbus_win_allocate_fd (void)
385 {
386   int i;
387
388   _DBUS_LOCK (win_fds);
389
390   if (win_fds == NULL)
391     {
392 #ifdef _DBUS_WIN_USE_RANDOMIZER
393       DBusString random;
394 #endif
395
396       win_n_fds = 16;
397       /* Use malloc to avoid memory leak failure in dbus-test */
398       win_fds = malloc (win_n_fds * sizeof (*win_fds));
399
400       _dbus_assert (win_fds != NULL);
401
402       for (i = 0; i < win_n_fds; i++)
403         win_fds[i].is_used = 0;
404
405 #ifdef _DBUS_WIN_USE_RANDOMIZER
406
407       _dbus_string_init (&random);
408       _dbus_generate_random_bytes (&random, sizeof (int));
409       memmove (&win_encap_randomizer, _dbus_string_get_const_data (&random), sizeof (int));
410       win_encap_randomizer &= 0xFF;
411       _dbus_string_free (&random);
412 #endif
413
414     }
415
416   for (i = 0; i < win_n_fds && win_fds[i].is_used != 0; i++)
417     ;
418
419   if (i == win_n_fds)
420     {
421       int oldn = win_n_fds;
422       int j;
423
424       win_n_fds += 16;
425       win_fds = realloc (win_fds, win_n_fds * sizeof (*win_fds));
426
427       _dbus_assert (win_fds != NULL);
428
429       for (j = oldn; j < win_n_fds; j++)
430         win_fds[i].is_used = 0;
431     }
432
433   memset(&win_fds[i], 0, sizeof(win_fds[i]));
434
435   win_fds[i].is_used = 1;
436   win_fds[i].fd = -1;
437   win_fds[i].port_file_fd = -1;
438   win_fds[i].close_on_exec = FALSE;
439   win_fds[i].non_blocking = FALSE;
440
441   _DBUS_UNLOCK (win_fds);
442
443   return i;
444 }
445
446 static
447 int
448 _dbus_create_handle_from_socket (int s)
449 {
450   int i;
451   int handle = -1;
452
453   // check: parameter must be a valid value
454   _dbus_assert(s != -1);
455   _dbus_assert(!IS_HANDLE(s));
456
457   // get index of a new position in the map
458   i = _dbus_win_allocate_fd ();
459
460   // fill new posiiton in the map: value->index
461   win_fds[i].fd = s;
462   win_fds[i].is_used = 1;
463
464   // create handle from the index: index->handle
465   handle = TO_HANDLE (i);
466
467   _dbus_verbose ("_dbus_create_handle_from_value, value: %d, handle: %d\n", s, handle);
468
469   return handle;
470 }
471
472 int
473 _dbus_socket_to_handle (DBusSocket *s)
474 {
475   int i;
476   int handle = -1;
477
478   // check: parameter must be a valid socket
479   _dbus_assert(s != NULL);
480   _dbus_assert(s->fd != -1);
481   _dbus_assert(!IS_HANDLE(s->fd));
482
483   _DBUS_LOCK (win_fds);
484
485   // at the first call there is no win_fds
486   // will be constructed  _dbus_create_handle_from_socket
487   // because handle = -1
488   if (win_fds != NULL)
489     {
490       // search for the value in the map
491       // find the index of the value: value->index
492       for (i = 0; i < win_n_fds; i++)
493         if (win_fds[i].is_used == 1 && win_fds[i].fd == s->fd)
494           {
495             // create handle from the index: index->handle
496             handle = TO_HANDLE (i);
497             break;
498           }
499     }
500   _DBUS_UNLOCK (win_fds);
501
502
503   if (handle == -1)
504     {
505       handle = _dbus_create_handle_from_socket(s->fd);
506     }
507
508   _dbus_assert(handle != -1);
509
510   return handle;
511 }
512
513 static
514 void 
515 _dbus_handle_to_socket_unlocked (int          handle,
516                                  DBusSocket **ptr)
517 {
518   int i;
519
520   // check: parameter must be a valid handle
521   _dbus_assert(handle != -1);
522   _dbus_assert(IS_HANDLE(handle));
523   _dbus_assert(ptr != NULL);
524
525   // map from handle to index: handle->index
526   i = FROM_HANDLE (handle);
527
528   _dbus_assert (win_fds != NULL);
529   _dbus_assert (i >= 0 && i < win_n_fds);
530
531   // check for if fd is valid
532   _dbus_assert (win_fds[i].is_used == 1);
533
534   // get socket from index: index->socket
535   *ptr = &win_fds[i];
536
537   _dbus_verbose ("_dbus_socket_to_handle_unlocked: socket=%d, handle=%d, index=%d\n", (*ptr)->fd, handle, i);
538 }
539
540 void 
541 _dbus_handle_to_socket (int          handle,
542                         DBusSocket **ptr)
543 {
544   _dbus_lock_sockets();
545   _dbus_handle_to_socket_unlocked (handle, ptr);
546   _dbus_unlock_sockets();
547 }
548
549
550 #undef TO_HANDLE
551 #undef IS_HANDLE
552 #undef FROM_HANDLE
553 #define FROM_HANDLE(n) 1==DBUS_WIN_DONT_USE__FROM_HANDLE__DIRECTLY
554 #define win_fds 1==DBUS_WIN_DONT_USE_win_fds_DIRECTLY
555
556
557 #endif
558
559 /**
560  * Thin wrapper around the read() system call that appends
561  * the data it reads to the DBusString buffer. It appends
562  * up to the given count, and returns the same value
563  * and same errno as read(). The only exception is that
564  * _dbus_read() handles EINTR for you. _dbus_read() can
565  * return ENOMEM, even though regular UNIX read doesn't.
566  *
567  * @param fd the file descriptor to read from
568  * @param buffer the buffer to append data to
569  * @param count the amount of data to read
570  * @returns the number of bytes read or -1
571  */
572 int
573 _dbus_read_socket (int               handle,
574                    DBusString       *buffer,
575                    int               count)
576 {
577 #ifdef ENABLE_DBUSSOCKET
578   DBusSocket *s;
579 #endif
580   int bytes_read;
581   int start;
582   char *data;
583
584   _dbus_assert (count >= 0);
585
586   start = _dbus_string_get_length (buffer);
587
588   if (!_dbus_string_lengthen (buffer, count))
589     {
590       errno = ENOMEM;
591       return -1;
592     }
593
594   data = _dbus_string_get_data_len (buffer, start, count);
595
596 #ifdef ENABLE_DBUSSOCKET
597   _dbus_handle_to_socket(handle, &s);
598
599   if(s->is_used)
600     {
601       _dbus_verbose ("recv: count=%d socket=%d\n", count, s->fd);
602       bytes_read = recv (s->fd, data, count, 0);
603 #else
604         if(1)
605     {
606       _dbus_verbose ("recv: count=%d socket=%d\n", count, handle);
607       bytes_read = recv (handle, data, count, 0);
608 #endif
609       if (bytes_read == SOCKET_ERROR)
610         {
611           DBUS_SOCKET_SET_ERRNO();
612           _dbus_verbose ("recv: failed: %s\n", _dbus_strerror (errno));
613           bytes_read = -1;
614         }
615       else
616         _dbus_verbose ("recv: = %d\n", bytes_read);
617     }
618   else
619     {
620       _dbus_assert_not_reached ("no valid socket");
621     }
622
623   if (bytes_read < 0)
624     {
625       /* put length back (note that this doesn't actually realloc anything) */
626       _dbus_string_set_length (buffer, start);
627       return -1;
628     }
629   else
630     {
631       /* put length back (doesn't actually realloc) */
632       _dbus_string_set_length (buffer, start + bytes_read);
633
634 #if 0
635
636       if (bytes_read > 0)
637         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
638 #endif
639
640       return bytes_read;
641     }
642 }
643
644 /**
645  * Thin wrapper around the write() system call that writes a part of a
646  * DBusString and handles EINTR for you.
647  * 
648  * @param fd the file descriptor to write
649  * @param buffer the buffer to write data from
650  * @param start the first byte in the buffer to write
651  * @param len the number of bytes to try to write
652  * @returns the number of bytes written or -1 on error
653  */
654 int
655 _dbus_write_socket (int               handle,
656                     const DBusString *buffer,
657                     int               start,
658                     int               len)
659 {
660 #ifdef ENABLE_DBUSSOCKET
661   DBusSocket *s;
662 #endif
663   int is_used;
664   const char *data;
665   int bytes_written;
666
667   data = _dbus_string_get_const_data_len (buffer, start, len);
668
669 #ifdef ENABLE_DBUSSOCKET
670   _dbus_handle_to_socket(handle, &s);
671
672   if (s->is_used)
673     {
674       _dbus_verbose ("send: len=%d socket=%d\n", len, s->fd);
675       bytes_written = send (s->fd, data, len, 0);
676 #else
677   if (1)
678     {
679       _dbus_verbose ("send: len=%d socket=%d\n", len, handle);
680           bytes_written = send (handle, data, len, 0);
681 #endif
682       if (bytes_written == SOCKET_ERROR)
683         {
684           DBUS_SOCKET_SET_ERRNO();
685           _dbus_verbose ("send: failed: %s\n", _dbus_strerror (errno));
686           bytes_written = -1;
687         }
688       else
689         _dbus_verbose ("send: = %d\n", bytes_written);
690     }
691   else
692     {
693       _dbus_assert_not_reached ("unhandled fd type");
694     }
695
696 #if 0
697   if (bytes_written > 0)
698     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
699 #endif
700
701   return bytes_written;
702 }
703
704
705 /**
706  * Closes a file descriptor.
707  *
708  * @param fd the file descriptor
709  * @param error error object
710  * @returns #FALSE if error set
711  */
712 dbus_bool_t
713 _dbus_close_socket (int        handle,
714                     DBusError *error)
715 {
716 #ifdef ENABLE_DBUSSOCKET
717   DBusSocket *s;
718
719   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
720
721   _dbus_lock_sockets();
722
723   _dbus_handle_to_socket_unlocked (handle, &s);
724
725
726   if (s->is_used)
727     {
728       if (s->port_file_fd >= 0)
729         {
730           _chsize (s->port_file_fd, 0);
731           close (s->port_file_fd);
732           s->port_file_fd = -1;
733           unlink (_dbus_string_get_const_data (&s->port_file));
734           free ((char *) _dbus_string_get_const_data (&s->port_file));
735         }
736
737       if (closesocket (s->fd) == SOCKET_ERROR)
738         {
739           DBUS_SOCKET_SET_ERRNO ();
740           dbus_set_error (error, _dbus_error_from_errno (errno),
741               "Could not close socket: socket=%d, handle=%d, %s",
742                           s->fd, handle, _dbus_strerror (errno));
743           _dbus_unlock_sockets();
744           return FALSE;
745         }
746       _dbus_verbose ("_dbus_close_socket: socket=%d, handle=%d\n",
747                      s->fd, handle);
748     }
749   else
750     {
751       _dbus_assert_not_reached ("unhandled fd type");
752     }
753
754   _dbus_unlock_sockets();
755
756   _dbus_win_deallocate_fd (handle);
757
758   return TRUE;
759
760 #else
761
762   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
763
764
765   if (1)
766     {
767       if (closesocket (handle) == SOCKET_ERROR)
768         {
769           DBUS_SOCKET_SET_ERRNO ();
770           dbus_set_error (error, _dbus_error_from_errno (errno),
771               "Could not close socket: socket=%d, , %s",
772                           handle, _dbus_strerror (errno));
773           return FALSE;
774         }
775       _dbus_verbose ("_dbus_close_socket: socket=%d, \n",
776                      handle);
777     }
778   else
779     {
780       _dbus_assert_not_reached ("unhandled fd type");
781     }
782
783   return TRUE;
784 #endif
785
786 }
787
788 /**
789  * Sets the file descriptor to be close
790  * on exec. Should be called for all file
791  * descriptors in D-Bus code.
792  *
793  * @param fd the file descriptor
794  */
795 void
796 _dbus_fd_set_close_on_exec (int handle)
797 {
798 #ifdef ENABLE_DBUSSOCKET
799   DBusSocket *s;
800   if (handle < 0)
801     return;
802
803   _dbus_lock_sockets();
804
805   _dbus_handle_to_socket_unlocked (handle, &s);
806   s->close_on_exec = TRUE;
807
808   _dbus_unlock_sockets();
809 #else
810   /* TODO unic code.
811   int val;
812   
813   val = fcntl (fd, F_GETFD, 0);
814   
815   if (val < 0)
816     return;
817
818   val |= FD_CLOEXEC;
819   
820   fcntl (fd, F_SETFD, val);
821   */
822 #endif
823 }
824
825 /**
826  * Sets a file descriptor to be nonblocking.
827  *
828  * @param fd the file descriptor.
829  * @param error address of error location.
830  * @returns #TRUE on success.
831  */
832 dbus_bool_t
833 _dbus_set_fd_nonblocking (int             handle,
834                           DBusError      *error)
835 {
836 #ifdef ENABLE_DBUSSOCKET
837   DBusSocket *s;
838   u_long one = 1;
839
840   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
841
842   _dbus_lock_sockets();
843
844   _dbus_handle_to_socket_unlocked(handle, &s);
845
846   if (s->is_used)
847     {
848       if (ioctlsocket (s->fd, FIONBIO, &one) == SOCKET_ERROR)
849         {
850           dbus_set_error (error, _dbus_error_from_errno (WSAGetLastError ()),
851                           "Failed to set socket %d:%d to nonblocking: %s", s->fd,
852                           _dbus_strerror (WSAGetLastError ()));
853           _dbus_unlock_sockets();
854           return FALSE;
855         }
856     }
857   else
858     {
859       _dbus_assert_not_reached ("unhandled fd type");
860     }
861
862   _dbus_unlock_sockets();
863
864   return TRUE;
865 #else
866   u_long one = 1;
867
868   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
869
870   if (1)
871     {
872       if (ioctlsocket (handle, FIONBIO, &one) == SOCKET_ERROR)
873         {
874           dbus_set_error (error, _dbus_error_from_errno (WSAGetLastError ()),
875                           "Failed to set socket %d:%d to nonblocking: %s", handle,
876                           _dbus_strerror (WSAGetLastError ()));
877           return FALSE;
878         }
879     }
880   else
881     {
882       _dbus_assert_not_reached ("unhandled fd type");
883     }
884   return TRUE;
885 #endif
886 }
887
888
889 /**
890  * Like _dbus_write() but will use writev() if possible
891  * to write both buffers in sequence. The return value
892  * is the number of bytes written in the first buffer,
893  * plus the number written in the second. If the first
894  * buffer is written successfully and an error occurs
895  * writing the second, the number of bytes in the first
896  * is returned (i.e. the error is ignored), on systems that
897  * don't have writev. Handles EINTR for you.
898  * The second buffer may be #NULL.
899  *
900  * @param fd the file descriptor
901  * @param buffer1 first buffer
902  * @param start1 first byte to write in first buffer
903  * @param len1 number of bytes to write from first buffer
904  * @param buffer2 second buffer, or #NULL
905  * @param start2 first byte to write in second buffer
906  * @param len2 number of bytes to write in second buffer
907  * @returns total bytes written from both buffers, or -1 on error
908  */
909 int
910 _dbus_write_socket_two (int               handle,
911                         const DBusString *buffer1,
912                         int               start1,
913                         int               len1,
914                         const DBusString *buffer2,
915                         int               start2,
916                         int               len2)
917 {
918 #ifdef ENABLE_DBUSSOCKET
919   DBusSocket *s;
920   WSABUF vectors[2];
921   const char *data1;
922   const char *data2;
923   int rc;
924   DWORD bytes_written;
925   int ret1;
926
927   _dbus_assert (buffer1 != NULL);
928   _dbus_assert (start1 >= 0);
929   _dbus_assert (start2 >= 0);
930   _dbus_assert (len1 >= 0);
931   _dbus_assert (len2 >= 0);
932
933   _dbus_handle_to_socket(handle, &s);
934
935   data1 = _dbus_string_get_const_data_len (buffer1, start1, len1);
936
937   if (buffer2 != NULL)
938     data2 = _dbus_string_get_const_data_len (buffer2, start2, len2);
939   else
940     {
941       data2 = NULL;
942       start2 = 0;
943       len2 = 0;
944     }
945
946   if (s->is_used)
947     {
948       vectors[0].buf = (char*) data1;
949       vectors[0].len = len1;
950       vectors[1].buf = (char*) data2;
951       vectors[1].len = len2;
952
953       _dbus_verbose ("WSASend: len1+2=%d+%d socket=%d\n", len1, len2, s->fd);
954       rc = WSASend (s->fd, vectors, data2 ? 2 : 1, &bytes_written,
955                     0, NULL, NULL);
956       if (rc < 0)
957         {
958           DBUS_SOCKET_SET_ERRNO ();
959           _dbus_verbose ("WSASend: failed: %s\n", _dbus_strerror (errno));
960           bytes_written = -1;
961         }
962       else
963         _dbus_verbose ("WSASend: = %ld\n", bytes_written);
964       return bytes_written;
965     }
966   else
967     {
968       _dbus_assert_not_reached ("unhandled fd type");
969     }
970   return 0;
971 #else
972   WSABUF vectors[2];
973   const char *data1;
974   const char *data2;
975   int rc;
976   DWORD bytes_written;
977   int ret1;
978
979   _dbus_assert (buffer1 != NULL);
980   _dbus_assert (start1 >= 0);
981   _dbus_assert (start2 >= 0);
982   _dbus_assert (len1 >= 0);
983   _dbus_assert (len2 >= 0);
984
985
986   data1 = _dbus_string_get_const_data_len (buffer1, start1, len1);
987
988   if (buffer2 != NULL)
989     data2 = _dbus_string_get_const_data_len (buffer2, start2, len2);
990   else
991     {
992       data2 = NULL;
993       start2 = 0;
994       len2 = 0;
995     }
996
997   if (1)
998     {
999       vectors[0].buf = (char*) data1;
1000       vectors[0].len = len1;
1001       vectors[1].buf = (char*) data2;
1002       vectors[1].len = len2;
1003
1004       _dbus_verbose ("WSASend: len1+2=%d+%d socket=%d\n", len1, len2, handle);
1005       rc = WSASend (handle, vectors, data2 ? 2 : 1, &bytes_written,
1006                     0, NULL, NULL);
1007       if (rc < 0)
1008         {
1009           DBUS_SOCKET_SET_ERRNO ();
1010           _dbus_verbose ("WSASend: failed: %s\n", _dbus_strerror (errno));
1011           bytes_written = -1;
1012         }
1013       else
1014         _dbus_verbose ("WSASend: = %ld\n", bytes_written);
1015       return bytes_written;
1016     }
1017   else
1018     {
1019       _dbus_assert_not_reached ("unhandled fd type");
1020     }
1021   return 0;
1022 #endif
1023 }
1024
1025 #if 0
1026
1027 /**
1028  * Opens the client side of a Windows named pipe. The connection D-BUS
1029  * file descriptor index is returned. It is set up as nonblocking.
1030  * 
1031  * @param path the path to named pipe socket
1032  * @param error return location for error code
1033  * @returns connection D-BUS file descriptor or -1 on error
1034  */
1035 int
1036 _dbus_connect_named_pipe (const char     *path,
1037                           DBusError      *error)
1038 {
1039   _dbus_assert_not_reached ("not implemented");
1040 }
1041
1042 #endif
1043
1044
1045 #ifdef ENABLE_DBUSUSERINFO
1046 dbus_bool_t
1047 _dbus_account_to_win_sid (const wchar_t  *waccount,
1048                           void          **ppsid,
1049                           DBusError      *error)
1050 {
1051   dbus_bool_t retval = FALSE;
1052   DWORD sid_length, wdomain_length;
1053   SID_NAME_USE use;
1054   wchar_t *wdomain;
1055
1056   *ppsid = NULL;
1057
1058   sid_length = 0;
1059   wdomain_length = 0;
1060   if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length,
1061                            NULL, &wdomain_length, &use)
1062       && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1063     {
1064       _dbus_win_set_error_from_win_error (error, GetLastError ());
1065       return FALSE;
1066     }
1067
1068   *ppsid = dbus_malloc (sid_length);
1069   if (!*ppsid)
1070     {
1071       _DBUS_SET_OOM (error);
1072       return FALSE;
1073     }
1074
1075   wdomain = dbus_new (wchar_t, wdomain_length);
1076   if (!wdomain)
1077     {
1078       _DBUS_SET_OOM (error);
1079       goto out1;
1080     }
1081
1082   if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length,
1083                            wdomain, &wdomain_length, &use))
1084     {
1085       _dbus_win_set_error_from_win_error (error, GetLastError ());
1086       goto out2;
1087     }
1088
1089   if (!IsValidSid ((PSID) *ppsid))
1090     {
1091       dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
1092       goto out2;
1093     }
1094
1095   retval = TRUE;
1096
1097 out2:
1098   dbus_free (wdomain);
1099 out1:
1100   if (!retval)
1101     {
1102       dbus_free (*ppsid);
1103       *ppsid = NULL;
1104     }
1105
1106   return retval;
1107 }
1108
1109 dbus_bool_t
1110 fill_win_user_info_name_and_groups (wchar_t       *wname,
1111                                     wchar_t       *wdomain,
1112                                     DBusUserInfo *info,
1113                                     DBusError    *error)
1114 {
1115 #ifdef DBUS_WINCE
1116         return TRUE;
1117 #else
1118   dbus_bool_t retval = FALSE;
1119   char *name, *domain;
1120   LPLOCALGROUP_USERS_INFO_0 local_groups = NULL;
1121   LPGROUP_USERS_INFO_0 global_groups = NULL;
1122   DWORD nread, ntotal;
1123
1124   name = _dbus_win_utf16_to_utf8 (wname, error);
1125   if (!name)
1126     return FALSE;
1127
1128   domain = _dbus_win_utf16_to_utf8 (wdomain, error);
1129   if (!domain)
1130     goto out0;
1131
1132   info->username = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
1133   if (!info->username)
1134     {
1135       _DBUS_SET_OOM (error);
1136       goto out1;
1137     }
1138
1139   strcpy (info->username, domain);
1140   strcat (info->username, "\\");
1141   strcat (info->username, name);
1142
1143   info->n_group_ids = 0;
1144   if (NetUserGetLocalGroups (NULL, wname, 0, LG_INCLUDE_INDIRECT,
1145                              (LPBYTE *) &local_groups, MAX_PREFERRED_LENGTH,
1146                              &nread, &ntotal) == NERR_Success)
1147     {
1148       DWORD i;
1149       int n;
1150
1151       info->group_ids = dbus_new (dbus_gid_t, nread);
1152       if (!info->group_ids)
1153         {
1154           _DBUS_SET_OOM (error);
1155           goto out3;
1156         }
1157
1158       for (i = n = 0; i < nread; i++)
1159         {
1160           PSID group_sid;
1161           if (_dbus_account_to_win_sid (local_groups[i].lgrui0_name,
1162                                         &group_sid, error))
1163             {
1164               info->group_ids[n++] = _dbus_win_sid_to_uid_t (group_sid);
1165               dbus_free (group_sid);
1166             }
1167         }
1168       info->n_group_ids = n;
1169     }
1170
1171   if (NetUserGetGroups (NULL, wname, 0,
1172                         (LPBYTE *) &global_groups, MAX_PREFERRED_LENGTH,
1173                         &nread, &ntotal) == NERR_Success)
1174     {
1175       DWORD i;
1176       int n = info->n_group_ids;
1177
1178       info->group_ids = dbus_realloc (info->group_ids, (n + nread) * sizeof (dbus_gid_t));
1179       if (!info->group_ids)
1180         {
1181           _DBUS_SET_OOM (error);
1182           goto out4;
1183         }
1184
1185       for (i = 0; i < nread; i++)
1186         {
1187           PSID group_sid;
1188           if (_dbus_account_to_win_sid (global_groups[i].grui0_name,
1189                                         &group_sid, error))
1190             {
1191               info->group_ids[n++] = _dbus_win_sid_to_uid_t (group_sid);
1192               dbus_free (group_sid);
1193             }
1194         }
1195       info->n_group_ids = n;
1196     }
1197
1198   if (info->n_group_ids > 0)
1199     {
1200       /* FIXME: find out actual primary group */
1201       info->primary_gid = info->group_ids[0];
1202     }
1203   else
1204     {
1205       info->group_ids = dbus_new (dbus_gid_t, 1);
1206       info->n_group_ids = 1;
1207       info->group_ids[0] = DBUS_GID_UNSET;
1208       info->primary_gid = DBUS_GID_UNSET;
1209     }
1210
1211   retval = TRUE;
1212
1213 out4:
1214   if (global_groups != NULL)
1215     NetApiBufferFree (global_groups);
1216 out3:
1217   if (local_groups != NULL)
1218     NetApiBufferFree (local_groups);
1219 out1:
1220   dbus_free (domain);
1221 out0:
1222   dbus_free (name);
1223
1224   return retval;
1225 #endif //DBUS_WINCE
1226 }
1227
1228 dbus_bool_t
1229 fill_win_user_info_homedir (wchar_t      *wname,
1230                             wchar_t      *wdomain,
1231                             DBusUserInfo *info,
1232                             DBusError    *error)
1233 {
1234 #ifdef DBUS_WINCE
1235         //TODO
1236         return TRUE;
1237 #else
1238   dbus_bool_t retval = FALSE;
1239   USER_INFO_1 *user_info = NULL;
1240   wchar_t wcomputername[MAX_COMPUTERNAME_LENGTH + 1];
1241   DWORD wcomputername_length = MAX_COMPUTERNAME_LENGTH + 1;
1242   dbus_bool_t local_computer;
1243   wchar_t *dc = NULL;
1244   NET_API_STATUS ret = 0;
1245
1246   /* If the domain is this computer's name, assume it's a local user.
1247    * Otherwise look up a DC for the domain, and ask it.
1248    */
1249
1250   GetComputerNameW (wcomputername, &wcomputername_length);
1251   local_computer = (wcsicmp (wcomputername, wdomain) == 0);
1252
1253   if (!local_computer)
1254     {
1255       ret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &dc);
1256       if (ret != NERR_Success)
1257         {
1258           info->homedir = _dbus_strdup ("\\");
1259           _dbus_verbose("NetGetAnyDCName() failed with errorcode %d '%s'\n",ret,_dbus_lm_strerror(ret));
1260           return TRUE;
1261         }
1262     }
1263
1264   /* No way to find out the profile of another user, let's try the
1265    * "home directory" from NetUserGetInfo's USER_INFO_1.
1266    */
1267   ret = NetUserGetInfo (dc, wname, 1, (LPBYTE *) &user_info);
1268   if (ret == NERR_Success )
1269     if(user_info->usri1_home_dir != NULL &&
1270         user_info->usri1_home_dir != (LPWSTR)0xfeeefeee &&  /* freed memory http://www.gamedev.net/community/forums/topic.asp?topic_id=158402 */
1271         user_info->usri1_home_dir[0] != '\0')
1272       {
1273         info->homedir = _dbus_win_utf16_to_utf8 (user_info->usri1_home_dir, error);
1274         if (!info->homedir)
1275           goto out1;
1276       }
1277     else
1278       {
1279         _dbus_verbose("NetUserGetInfo() returned no home dir entry\n");
1280         /* Not set, so use something random. */
1281         info->homedir = _dbus_strdup ("\\");
1282       }
1283   else
1284     {
1285       char *dc_string = _dbus_win_utf16_to_utf8(dc,error);
1286           char *user_name = _dbus_win_utf16_to_utf8(wname,error);
1287       _dbus_verbose("NetUserGetInfo() for user '%s' failed with errorcode %d '%s', %s\n",user_name, ret,_dbus_lm_strerror(ret),dc_string);
1288       dbus_free(user_name);
1289       dbus_free(dc_string);
1290       /* Not set, so use something random. */
1291       info->homedir = _dbus_strdup ("\\");
1292     }
1293
1294   retval = TRUE;
1295
1296 out1:
1297   if (dc != NULL)
1298     NetApiBufferFree (dc);
1299   if (user_info != NULL)
1300     NetApiBufferFree (user_info);
1301
1302   return retval;
1303 #endif //DBUS_WINCE
1304 }
1305
1306 dbus_bool_t
1307 fill_win_user_info_from_name (wchar_t      *wname,
1308                               DBusUserInfo *info,
1309                               DBusError    *error)
1310 {
1311 #ifdef DBUS_WINCE
1312         return TRUE;
1313         //TODO
1314 #else
1315   dbus_bool_t retval = FALSE;
1316   PSID sid;
1317   wchar_t *wdomain;
1318   DWORD sid_length, wdomain_length;
1319   SID_NAME_USE use;
1320
1321   sid_length = 0;
1322   wdomain_length = 0;
1323   if (!LookupAccountNameW (NULL, wname, NULL, &sid_length,
1324                            NULL, &wdomain_length, &use) &&
1325       GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1326     {
1327       _dbus_win_set_error_from_win_error (error, GetLastError ());
1328       return FALSE;
1329     }
1330
1331   sid = dbus_malloc (sid_length);
1332   if (!sid)
1333     {
1334       _DBUS_SET_OOM (error);
1335       return FALSE;
1336     }
1337
1338   wdomain = dbus_new (wchar_t, wdomain_length);
1339   if (!wdomain)
1340     {
1341       _DBUS_SET_OOM (error);
1342       goto out0;
1343     }
1344
1345   if (!LookupAccountNameW (NULL, wname, sid, &sid_length,
1346                            wdomain, &wdomain_length, &use))
1347     {
1348       _dbus_win_set_error_from_win_error (error, GetLastError ());
1349       goto out1;
1350     }
1351
1352   if (!IsValidSid (sid))
1353     {
1354       dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
1355       goto out1;
1356     }
1357
1358   info->uid = _dbus_win_sid_to_uid_t (sid);
1359
1360   if (!fill_win_user_info_name_and_groups (wname, wdomain, info, error))
1361     goto out1;
1362
1363   if (!fill_win_user_info_homedir (wname, wdomain, info, error))
1364     goto out1;
1365
1366   retval = TRUE;
1367
1368 out1:
1369   dbus_free (wdomain);
1370 out0:
1371   dbus_free (sid);
1372
1373   return retval;
1374 #endif //DBUS_WINCE
1375 }
1376
1377 dbus_bool_t
1378 _dbus_win_sid_to_name_and_domain (dbus_uid_t uid,
1379                                   wchar_t  **wname,
1380                                   wchar_t  **wdomain,
1381                                   DBusError *error)
1382 {
1383 #ifdef DBUS_WINCE
1384         return TRUE;
1385         //TODO
1386 #else
1387   PSID sid;
1388   DWORD wname_length, wdomain_length;
1389   SID_NAME_USE use;
1390
1391   if (!_dbus_uid_t_to_win_sid (uid, &sid))
1392     {
1393       _dbus_win_set_error_from_win_error (error, GetLastError ());
1394       return FALSE;
1395     }
1396
1397   wname_length = 0;
1398   wdomain_length = 0;
1399   if (!LookupAccountSidW (NULL, sid, NULL, &wname_length,
1400                           NULL, &wdomain_length, &use) &&
1401       GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1402     {
1403       _dbus_win_set_error_from_win_error (error, GetLastError ());
1404       goto out0;
1405     }
1406
1407   *wname = dbus_new (wchar_t, wname_length);
1408   if (!*wname)
1409     {
1410       _DBUS_SET_OOM (error);
1411       goto out0;
1412     }
1413
1414   *wdomain = dbus_new (wchar_t, wdomain_length);
1415   if (!*wdomain)
1416     {
1417       _DBUS_SET_OOM (error);
1418       goto out1;
1419     }
1420
1421   if (!LookupAccountSidW (NULL, sid, *wname, &wname_length,
1422                           *wdomain, &wdomain_length, &use))
1423     {
1424       _dbus_win_set_error_from_win_error (error, GetLastError ());
1425       goto out2;
1426     }
1427
1428   return TRUE;
1429
1430 out2:
1431   dbus_free (*wdomain);
1432   *wdomain = NULL;
1433 out1:
1434   dbus_free (*wname);
1435   *wname = NULL;
1436 out0:
1437   LocalFree (sid);
1438
1439   return FALSE;
1440 #endif //DBUS_WINCE
1441 }
1442
1443 dbus_bool_t
1444 fill_win_user_info_from_uid (dbus_uid_t    uid,
1445                              DBusUserInfo *info,
1446                              DBusError    *error)
1447 {
1448 #ifdef DBUS_WINCE
1449         return TRUE;
1450         //TODO
1451 #else
1452   PSID sid;
1453   dbus_bool_t retval = FALSE;
1454   wchar_t *wname, *wdomain;
1455
1456   info->uid = uid;
1457
1458   if (!_dbus_win_sid_to_name_and_domain (uid, &wname, &wdomain, error))
1459     {
1460       _dbus_verbose("%s after _dbus_win_sid_to_name_and_domain\n",__FUNCTION__);
1461       return FALSE;
1462     }
1463
1464   if (!fill_win_user_info_name_and_groups (wname, wdomain, info, error))
1465     {
1466       _dbus_verbose("%s after fill_win_user_info_name_and_groups\n",__FUNCTION__);
1467       goto out0;
1468     }
1469
1470
1471   if (!fill_win_user_info_homedir (wname, wdomain, info, error))
1472     {
1473       _dbus_verbose("%s after fill_win_user_info_homedir\n",__FUNCTION__);
1474       goto out0;
1475     }
1476
1477   retval = TRUE;
1478
1479 out0:
1480   dbus_free (wdomain);
1481   dbus_free (wname);
1482
1483   return retval;
1484 #endif //DBUS_WINCE
1485 }
1486
1487 #endif
1488
1489
1490 void
1491 _dbus_win_startup_winsock (void)
1492 {
1493   /* Straight from MSDN, deuglified */
1494
1495   static dbus_bool_t beenhere = FALSE;
1496
1497   WORD wVersionRequested;
1498   WSADATA wsaData;
1499   int err;
1500
1501   if (beenhere)
1502     return;
1503
1504   wVersionRequested = MAKEWORD (2, 0);
1505
1506   err = WSAStartup (wVersionRequested, &wsaData);
1507   if (err != 0)
1508     {
1509       _dbus_assert_not_reached ("Could not initialize WinSock");
1510       _dbus_abort ();
1511     }
1512
1513   /* Confirm that the WinSock DLL supports 2.0.  Note that if the DLL
1514    * supports versions greater than 2.0 in addition to 2.0, it will
1515    * still return 2.0 in wVersion since that is the version we
1516    * requested.
1517    */
1518   if (LOBYTE (wsaData.wVersion) != 2 ||
1519       HIBYTE (wsaData.wVersion) != 0)
1520     {
1521       _dbus_assert_not_reached ("No usable WinSock found");
1522       _dbus_abort ();
1523     }
1524
1525   beenhere = TRUE;
1526 }
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536 /************************************************************************
1537  
1538  UTF / string code
1539  
1540  ************************************************************************/
1541
1542 /**
1543  * Measure the message length without terminating nul 
1544  */
1545 int _dbus_printf_string_upper_bound (const char *format,
1546                                      va_list args)
1547 {
1548   /* MSVCRT's vsnprintf semantics are a bit different */
1549   /* The C library source in the Platform SDK indicates that this
1550    * would work, but alas, it doesn't. At least not on Windows
1551    * 2000. Presumably those sources correspond to the C library on
1552    * some newer or even future Windows version.
1553    *
1554     len = _vsnprintf (NULL, _DBUS_INT_MAX, format, args);
1555    */
1556   char p[1024];
1557   int len;
1558   len = _vsnprintf (p, sizeof(p)-1, format, args);
1559   if (len == -1) // try again
1560     {
1561       char *p;
1562       p = malloc (strlen(format)*3);
1563       len = _vsnprintf (p, sizeof(p)-1, format, args);
1564       free(p);
1565     }
1566   return len;
1567 }
1568
1569
1570 /**
1571  * Returns the UTF-16 form of a UTF-8 string. The result should be
1572  * freed with dbus_free() when no longer needed.
1573  *
1574  * @param str the UTF-8 string
1575  * @param error return location for error code
1576  */
1577 wchar_t *
1578 _dbus_win_utf8_to_utf16 (const char *str,
1579                          DBusError  *error)
1580 {
1581   DBusString s;
1582   int n;
1583   wchar_t *retval;
1584
1585   _dbus_string_init_const (&s, str);
1586
1587   if (!_dbus_string_validate_utf8 (&s, 0, _dbus_string_get_length (&s)))
1588     {
1589       dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid UTF-8");
1590       return NULL;
1591     }
1592
1593   n = MultiByteToWideChar (CP_UTF8, 0, str, -1, NULL, 0);
1594
1595   if (n == 0)
1596     {
1597       _dbus_win_set_error_from_win_error (error, GetLastError ());
1598       return NULL;
1599     }
1600
1601   retval = dbus_new (wchar_t, n);
1602
1603   if (!retval)
1604     {
1605       _DBUS_SET_OOM (error);
1606       return NULL;
1607     }
1608
1609   if (MultiByteToWideChar (CP_UTF8, 0, str, -1, retval, n) != n)
1610     {
1611       dbus_free (retval);
1612       dbus_set_error_const (error, DBUS_ERROR_FAILED, "MultiByteToWideChar inconsistency");
1613       return NULL;
1614     }
1615
1616   return retval;
1617 }
1618
1619 /**
1620  * Returns the UTF-8 form of a UTF-16 string. The result should be
1621  * freed with dbus_free() when no longer needed.
1622  *
1623  * @param str the UTF-16 string
1624  * @param error return location for error code
1625  */
1626 char *
1627 _dbus_win_utf16_to_utf8 (const wchar_t *str,
1628                          DBusError     *error)
1629 {
1630   int n;
1631   char *retval;
1632
1633   n = WideCharToMultiByte (CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
1634
1635   if (n == 0)
1636     {
1637       _dbus_win_set_error_from_win_error (error, GetLastError ());
1638       return NULL;
1639     }
1640
1641   retval = dbus_malloc (n);
1642
1643   if (!retval)
1644     {
1645       _DBUS_SET_OOM (error);
1646       return NULL;
1647     }
1648
1649   if (WideCharToMultiByte (CP_UTF8, 0, str, -1, retval, n, NULL, NULL) != n)
1650     {
1651       dbus_free (retval);
1652       dbus_set_error_const (error, DBUS_ERROR_FAILED, "WideCharToMultiByte inconsistency");
1653       return NULL;
1654     }
1655
1656   return retval;
1657 }
1658
1659
1660
1661
1662
1663
1664 /************************************************************************
1665  
1666  uid ... <-> win sid functions
1667  
1668  ************************************************************************/
1669
1670 dbus_bool_t
1671 _dbus_win_account_to_sid (const wchar_t *waccount,
1672                           void           **ppsid,
1673                           DBusError       *error)
1674 {
1675   dbus_bool_t retval = FALSE;
1676   DWORD sid_length, wdomain_length;
1677   SID_NAME_USE use;
1678   wchar_t *wdomain;
1679
1680   *ppsid = NULL;
1681
1682   sid_length = 0;
1683   wdomain_length = 0;
1684   if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length,
1685                            NULL, &wdomain_length, &use) &&
1686       GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1687     {
1688       _dbus_win_set_error_from_win_error (error, GetLastError ());
1689       return FALSE;
1690     }
1691
1692   *ppsid = dbus_malloc (sid_length);
1693   if (!*ppsid)
1694     {
1695       _DBUS_SET_OOM (error);
1696       return FALSE;
1697     }
1698
1699   wdomain = dbus_new (wchar_t, wdomain_length);
1700   if (!wdomain)
1701     {
1702       _DBUS_SET_OOM (error);
1703       goto out1;
1704     }
1705
1706   if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length,
1707                            wdomain, &wdomain_length, &use))
1708     {
1709       _dbus_win_set_error_from_win_error (error, GetLastError ());
1710       goto out2;
1711     }
1712
1713   if (!IsValidSid ((PSID) *ppsid))
1714     {
1715       dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
1716       goto out2;
1717     }
1718
1719   retval = TRUE;
1720
1721 out2:
1722   dbus_free (wdomain);
1723 out1:
1724   if (!retval)
1725     {
1726       dbus_free (*ppsid);
1727       *ppsid = NULL;
1728     }
1729
1730   return retval;
1731 }
1732
1733 #ifdef ENABLE_UID_TO_SID
1734 static void
1735 _sid_atom_cache_shutdown (void *unused)
1736 {
1737   DBusHashIter iter;
1738   _DBUS_LOCK (sid_atom_cache);
1739   _dbus_hash_iter_init (sid_atom_cache, &iter);
1740   while (_dbus_hash_iter_next (&iter))
1741     {
1742       ATOM atom;
1743       atom = (ATOM) _dbus_hash_iter_get_value (&iter);
1744       GlobalDeleteAtom(atom);
1745       _dbus_hash_iter_remove_entry(&iter);
1746     }
1747   _DBUS_UNLOCK (sid_atom_cache);
1748   _dbus_hash_table_unref (sid_atom_cache);
1749   sid_atom_cache = NULL;
1750 }
1751
1752 /**
1753  * Returns the 2-way associated dbus_uid_t form a SID.
1754  *
1755  * @param psid pointer to the SID
1756  */
1757 dbus_uid_t
1758 _dbus_win_sid_to_uid_t (PSID psid)
1759 {
1760   dbus_uid_t uid;
1761   dbus_uid_t olduid;
1762   char *string;
1763   ATOM atom;
1764
1765   if (!IsValidSid (psid))
1766     {
1767       _dbus_verbose("%s invalid sid\n",__FUNCTION__);
1768       return DBUS_UID_UNSET;
1769     }
1770   if (!ConvertSidToStringSidA (psid, &string))
1771     {
1772       _dbus_verbose("%s invalid sid\n",__FUNCTION__);
1773       return DBUS_UID_UNSET;
1774     }
1775
1776   atom = GlobalAddAtom(string);
1777
1778   if (atom == 0)
1779     {
1780       _dbus_verbose("%s GlobalAddAtom failed\n",__FUNCTION__);
1781       LocalFree (string);
1782       return DBUS_UID_UNSET;
1783     }
1784
1785   _DBUS_LOCK (sid_atom_cache);
1786
1787   if (sid_atom_cache == NULL)
1788     {
1789       sid_atom_cache = _dbus_hash_table_new (DBUS_HASH_ULONG, NULL, NULL);
1790       _dbus_register_shutdown_func (_sid_atom_cache_shutdown, NULL);
1791     }
1792
1793   uid = atom;
1794   olduid = (dbus_uid_t) _dbus_hash_table_lookup_ulong (sid_atom_cache, uid);
1795
1796   if (olduid)
1797     {
1798       _dbus_verbose("%s sid with id %i found in cache\n",__FUNCTION__, olduid);
1799       uid = olduid;
1800     }
1801   else
1802     {
1803       _dbus_hash_table_insert_ulong (sid_atom_cache, uid, (void*) uid);
1804       _dbus_verbose("%s sid %s added with uid %i to cache\n",__FUNCTION__, string, uid);
1805     }
1806
1807   _DBUS_UNLOCK (sid_atom_cache);
1808
1809   return uid;
1810 }
1811
1812 dbus_bool_t  _dbus_uid_t_to_win_sid (dbus_uid_t uid, PSID *ppsid)
1813 {
1814   void* atom;
1815   char string[255];
1816
1817   atom = _dbus_hash_table_lookup_ulong (sid_atom_cache, uid);
1818   if (atom == NULL)
1819     {
1820       _dbus_verbose("%s uid %i not found in cache\n",__FUNCTION__,uid);
1821       return FALSE;
1822     }
1823   memset( string, '.', sizeof(string) );
1824   if (!GlobalGetAtomNameA( (ATOM) atom, string, 255 ))
1825     {
1826       _dbus_verbose("%s uid %i not found in cache\n",__FUNCTION__, uid);
1827       return FALSE;
1828     }
1829   if (!ConvertStringSidToSidA(string, ppsid))
1830     {
1831       _dbus_verbose("%s could not convert %s into sid \n",__FUNCTION__, string);
1832       return FALSE;
1833     }
1834   _dbus_verbose("%s converted %s into sid \n",__FUNCTION__, string);
1835   return TRUE;
1836 }
1837 #endif
1838
1839 /** @} end of sysdeps-win */
1840
1841
1842 /** Gets our UID
1843  * @returns process UID
1844  */
1845 dbus_uid_t
1846 _dbus_getuid(void)
1847 {
1848 #ifndef ENABLE_UID_TO_SID
1849         return DBUS_UID_UNSET;
1850 #else
1851   dbus_uid_t retval = DBUS_UID_UNSET;
1852   HANDLE process_token = NULL;
1853   TOKEN_USER *token_user = NULL;
1854   DWORD n;
1855
1856   if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token))
1857     _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ());
1858   else if ((!GetTokenInformation (process_token, TokenUser, NULL, 0, &n)
1859             && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1860            || (token_user = alloca (n)) == NULL
1861            || !GetTokenInformation (process_token, TokenUser, token_user, n, &n))
1862     _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ());
1863   else
1864     retval = _dbus_win_sid_to_uid_t (token_user->User.Sid);
1865
1866   if (process_token != NULL)
1867     CloseHandle (process_token);
1868
1869   _dbus_verbose("_dbus_getuid() returns %d\n",retval);
1870   return retval;
1871 #endif
1872 }
1873
1874 /**
1875  * The only reason this is separate from _dbus_getpid() is to allow it
1876  * on Windows for logging but not for other purposes.
1877  * 
1878  * @returns process ID to put in log messages
1879  */
1880 unsigned long
1881 _dbus_pid_for_log (void)
1882 {
1883   return _dbus_getpid ();
1884 }
1885
1886
1887
1888 #ifdef DBUS_BUILD_TESTS
1889 /** Gets our GID
1890  * @returns process GID
1891  */
1892 dbus_gid_t
1893 _dbus_getgid (void)
1894 {
1895 #ifndef ENABLE_UID_TO_SID
1896         return DBUS_GID_UNSET;
1897 #else
1898   dbus_gid_t retval = DBUS_GID_UNSET;
1899   HANDLE process_token = NULL;
1900   TOKEN_PRIMARY_GROUP *token_primary_group = NULL;
1901   DWORD n;
1902
1903   if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token))
1904     _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ());
1905   else if ((!GetTokenInformation (process_token, TokenPrimaryGroup,
1906                                   NULL, 0, &n) &&
1907             GetLastError () != ERROR_INSUFFICIENT_BUFFER) ||
1908            (token_primary_group = alloca (n)) == NULL ||
1909            !GetTokenInformation (process_token, TokenPrimaryGroup,
1910                                  token_primary_group, n, &n))
1911     _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ());
1912   else
1913     retval = _dbus_win_sid_to_uid_t (token_primary_group->PrimaryGroup);
1914
1915   if (process_token != NULL)
1916     CloseHandle (process_token);
1917
1918   return retval;
1919 #endif
1920 }
1921
1922 #if 0
1923 dbus_bool_t
1924 _dbus_domain_test (const char *test_data_dir)
1925 {
1926   if (!_dbus_test_oom_handling ("spawn_nonexistent",
1927                                 check_spawn_nonexistent,
1928                                 NULL))
1929     return FALSE;
1930 }
1931
1932 #endif
1933
1934 #endif //DBUS_BUILD_TESTS
1935
1936 /************************************************************************
1937  
1938  pipes
1939  
1940  ************************************************************************/
1941
1942 /**
1943  * Creates a full-duplex pipe (as in socketpair()).
1944  * Sets both ends of the pipe nonblocking.
1945  *
1946  * @todo libdbus only uses this for the debug-pipe server, so in
1947  * principle it could be in dbus-sysdeps-util.c, except that
1948  * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
1949  * debug-pipe server is used.
1950  * 
1951  * @param fd1 return location for one end
1952  * @param fd2 return location for the other end
1953  * @param blocking #TRUE if pipe should be blocking
1954  * @param error error return
1955  * @returns #FALSE on failure (if error is set)
1956  */
1957 dbus_bool_t
1958 _dbus_full_duplex_pipe (int        *fd1,
1959                         int        *fd2,
1960                         dbus_bool_t blocking,
1961                         DBusError  *error)
1962 {
1963   SOCKET temp, socket1 = -1, socket2 = -1;
1964   struct sockaddr_in saddr;
1965   int len;
1966   u_long arg;
1967   fd_set read_set, write_set;
1968   struct timeval tv;
1969 #ifdef ENABLE_DBUSSOCKET
1970   DBusSocket sock;
1971 #endif
1972
1973
1974   _dbus_win_startup_winsock ();
1975
1976   temp = socket (AF_INET, SOCK_STREAM, 0);
1977   if (temp == INVALID_SOCKET)
1978     {
1979       DBUS_SOCKET_SET_ERRNO ();
1980       goto out0;
1981     }
1982
1983   arg = 1;
1984   if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR)
1985     {
1986       DBUS_SOCKET_SET_ERRNO ();
1987       goto out0;
1988     }
1989
1990   _DBUS_ZERO (saddr);
1991   saddr.sin_family = AF_INET;
1992   saddr.sin_port = 0;
1993   saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1994
1995   if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr)))
1996     {
1997       DBUS_SOCKET_SET_ERRNO ();
1998       goto out0;
1999     }
2000
2001   if (listen (temp, 1) == SOCKET_ERROR)
2002     {
2003       DBUS_SOCKET_SET_ERRNO ();
2004       goto out0;
2005     }
2006
2007   len = sizeof (saddr);
2008   if (getsockname (temp, (struct sockaddr *)&saddr, &len))
2009     {
2010       DBUS_SOCKET_SET_ERRNO ();
2011       goto out0;
2012     }
2013
2014   socket1 = socket (AF_INET, SOCK_STREAM, 0);
2015   if (socket1 == INVALID_SOCKET)
2016     {
2017       DBUS_SOCKET_SET_ERRNO ();
2018       goto out0;
2019     }
2020
2021   arg = 1;
2022   if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
2023     {
2024       DBUS_SOCKET_SET_ERRNO ();
2025       goto out1;
2026     }
2027
2028   if (connect (socket1, (struct sockaddr  *)&saddr, len) != SOCKET_ERROR ||
2029       WSAGetLastError () != WSAEWOULDBLOCK)
2030     {
2031       DBUS_SOCKET_SET_ERRNO ();
2032       goto out1;
2033     }
2034
2035   FD_ZERO (&read_set);
2036   FD_SET (temp, &read_set);
2037
2038   tv.tv_sec = 0;
2039   tv.tv_usec = 0;
2040
2041   if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR)
2042     {
2043       DBUS_SOCKET_SET_ERRNO ();
2044       goto out1;
2045     }
2046
2047   _dbus_assert (FD_ISSET (temp, &read_set));
2048
2049   socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
2050   if (socket2 == INVALID_SOCKET)
2051     {
2052       DBUS_SOCKET_SET_ERRNO ();
2053       goto out1;
2054     }
2055
2056   FD_ZERO (&write_set);
2057   FD_SET (socket1, &write_set);
2058
2059   tv.tv_sec = 0;
2060   tv.tv_usec = 0;
2061
2062   if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR)
2063     {
2064       DBUS_SOCKET_SET_ERRNO ();
2065       goto out2;
2066     }
2067
2068   _dbus_assert (FD_ISSET (socket1, &write_set));
2069
2070   if (blocking)
2071     {
2072       arg = 0;
2073       if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
2074         {
2075           DBUS_SOCKET_SET_ERRNO ();
2076           goto out2;
2077         }
2078
2079       arg = 0;
2080       if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR)
2081         {
2082           DBUS_SOCKET_SET_ERRNO ();
2083           goto out2;
2084         }
2085     }
2086   else
2087     {
2088       arg = 1;
2089       if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR)
2090         {
2091           DBUS_SOCKET_SET_ERRNO ();
2092           goto out2;
2093         }
2094     }
2095
2096 #ifdef ENABLE_DBUSSOCKET
2097   sock.fd = socket1;
2098   *fd1 = _dbus_socket_to_handle (&sock);
2099   sock.fd = socket2;
2100   *fd2 = _dbus_socket_to_handle (&sock);
2101 #else
2102   *fd1 = socket1;
2103   *fd2 = socket2;
2104 #endif
2105
2106   _dbus_verbose ("full-duplex pipe %d:%d <-> %d:%d\n",
2107                  *fd1, socket1, *fd2, socket2);
2108
2109   closesocket (temp);
2110
2111   return TRUE;
2112
2113 out2:
2114   closesocket (socket2);
2115 out1:
2116   closesocket (socket1);
2117 out0:
2118   closesocket (temp);
2119
2120   dbus_set_error (error, _dbus_error_from_errno (errno),
2121                   "Could not setup socket pair: %s",
2122                   _dbus_strerror (errno));
2123
2124   return FALSE;
2125 }
2126
2127 /**
2128  * Wrapper for poll().
2129  *
2130  * @param fds the file descriptors to poll
2131  * @param n_fds number of descriptors in the array
2132  * @param timeout_milliseconds timeout or -1 for infinite
2133  * @returns numbers of fds with revents, or <0 on error
2134  */
2135 #define USE_CHRIS_IMPL 0
2136 #if USE_CHRIS_IMPL
2137 int
2138 _dbus_poll (DBusPollFD *fds,
2139             int         n_fds,
2140             int         timeout_milliseconds)
2141 {
2142 #define DBUS_POLL_CHAR_BUFFER_SIZE 2000
2143   char msg[DBUS_POLL_CHAR_BUFFER_SIZE];
2144   char *msgp;
2145
2146   int ret = 0;
2147   int i;
2148   struct timeval tv;
2149   int ready;
2150
2151 #define DBUS_STACK_WSAEVENTS 256
2152   WSAEVENT eventsOnStack[DBUS_STACK_WSAEVENTS];
2153   WSAEVENT *pEvents = NULL;
2154   if (n_fds > DBUS_STACK_WSAEVENTS)
2155     pEvents = calloc(sizeof(WSAEVENT), n_fds);
2156   else
2157     pEvents = eventsOnStack;
2158
2159   _dbus_lock_sockets();
2160
2161 #ifdef DBUS_ENABLE_VERBOSE_MODE
2162   msgp = msg;
2163   msgp += sprintf (msgp, "WSAEventSelect: to=%d\n\t", timeout_milliseconds);
2164   for (i = 0; i < n_fds; i++)
2165     {
2166       static dbus_bool_t warned = FALSE;
2167       DBusSocket *s;
2168       DBusPollFD *fdp = &fds[i];
2169
2170       _dbus_handle_to_socket_unlocked(fdp->fd, &s);  
2171
2172       if (s->is_used == 0)
2173         {
2174           _dbus_warn ("no valid socket");
2175           warned = TRUE;
2176         }
2177
2178       if (fdp->events & _DBUS_POLLIN)
2179         msgp += sprintf (msgp, "R:%d ", s->fd);
2180
2181       if (fdp->events & _DBUS_POLLOUT)
2182         msgp += sprintf (msgp, "W:%d ", s->fd);
2183
2184       msgp += sprintf (msgp, "E:%d\n\t", s->fd);
2185
2186       // FIXME: more robust code for long  msg
2187       //        create on heap when msg[] becomes too small
2188       if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE)
2189         {
2190           _dbus_assert_not_reached ("buffer overflow in _dbus_poll");
2191         }
2192     }
2193
2194   msgp += sprintf (msgp, "\n");
2195   _dbus_verbose ("%s",msg);
2196 #endif
2197   for (i = 0; i < n_fds; i++)
2198     {
2199       DBusSocket *s;
2200       DBusPollFD *fdp = &fds[i];
2201       WSAEVENT ev;
2202       long lNetworkEvents = FD_OOB;
2203
2204       _dbus_handle_to_socket_unlocked(fdp->fd, &s); 
2205
2206       if (s->is_used == 0)
2207         continue;
2208
2209       ev = WSACreateEvent();
2210
2211       if (fdp->events & _DBUS_POLLIN)
2212         lNetworkEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
2213
2214       if (fdp->events & _DBUS_POLLOUT)
2215         lNetworkEvents |= FD_WRITE | FD_CONNECT;
2216
2217       WSAEventSelect(s->fd, ev, lNetworkEvents);
2218
2219       pEvents[i] = ev;
2220     }
2221
2222   _dbus_unlock_sockets();
2223
2224   ready = WSAWaitForMultipleEvents (n_fds, pEvents, FALSE, timeout_milliseconds, FALSE);
2225
2226   if (DBUS_SOCKET_API_RETURNS_ERROR (ready))
2227     {
2228       DBUS_SOCKET_SET_ERRNO ();
2229       if (errno != EWOULDBLOCK)
2230         _dbus_verbose ("WSAWaitForMultipleEvents: failed: %s\n", _dbus_strerror (errno));
2231       ret = -1;
2232     }
2233   else if (ready == WSA_WAIT_TIMEOUT)
2234     {
2235       _dbus_verbose ("WSAWaitForMultipleEvents: WSA_WAIT_TIMEOUT\n");
2236       ret = 0;
2237     }
2238   else if (ready >= WSA_WAIT_EVENT_0 && ready < (int)(WSA_WAIT_EVENT_0 + n_fds))
2239     {
2240       msgp = msg;
2241       msgp += sprintf (msgp, "WSAWaitForMultipleEvents: =%d\n\t", ready);
2242
2243       _dbus_lock_sockets();
2244       for (i = 0; i < n_fds; i++)
2245         {
2246           DBusSocket *s;
2247           DBusPollFD *fdp = &fds[i];
2248           WSANETWORKEVENTS ne;
2249
2250           _dbus_handle_to_socket_unlocked(fdp->fd, &s); 
2251
2252           fdp->revents = 0;
2253
2254           WSAEnumNetworkEvents(s->fd, pEvents[i], &ne);
2255
2256           if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
2257             fdp->revents |= _DBUS_POLLIN;
2258
2259           if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT))
2260             fdp->revents |= _DBUS_POLLOUT;
2261
2262           if (ne.lNetworkEvents & (FD_OOB))
2263             fdp->revents |= _DBUS_POLLERR;
2264
2265           if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
2266               msgp += sprintf (msgp, "R:%d ", s->fd);
2267
2268           if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT))
2269               msgp += sprintf (msgp, "W:%d ", s->fd);
2270
2271           if (ne.lNetworkEvents & (FD_OOB))
2272               msgp += sprintf (msgp, "E:%d ", s->fd);
2273
2274           msgp += sprintf (msgp, "lNetworkEvents:%d ", ne.lNetworkEvents);
2275
2276           if(ne.lNetworkEvents)
2277             ret++;
2278
2279           WSAEventSelect(s->fd, pEvents[i], 0);
2280         }
2281       _dbus_unlock_sockets();
2282
2283       msgp += sprintf (msgp, "\n");
2284       _dbus_verbose ("%s",msg);
2285     }
2286   else
2287     {
2288       _dbus_verbose ("WSAWaitForMultipleEvents: failed for unknown reason!");
2289       ret = -1;
2290     }
2291
2292   for(i = 0; i < n_fds; i++)
2293     {
2294       WSACloseEvent(pEvents[i]);
2295     }
2296
2297   if (n_fds > DBUS_STACK_WSAEVENTS)
2298     free(pEvents);
2299
2300   return ret;
2301 }
2302
2303 #else   // USE_CHRIS_IMPL
2304
2305 #ifdef ENABLE_DBUSSOCKET
2306
2307 int
2308 _dbus_poll (DBusPollFD *fds,
2309             int         n_fds,
2310             int         timeout_milliseconds)
2311 {
2312 #define DBUS_POLL_CHAR_BUFFER_SIZE 2000
2313   char msg[DBUS_POLL_CHAR_BUFFER_SIZE];
2314   char *msgp;
2315
2316   fd_set read_set, write_set, err_set;
2317   int max_fd = 0;
2318   int i;
2319   struct timeval tv;
2320   int ready;
2321
2322   FD_ZERO (&read_set);
2323   FD_ZERO (&write_set);
2324   FD_ZERO (&err_set);
2325
2326   _dbus_lock_sockets();
2327
2328 #ifdef DBUS_ENABLE_VERBOSE_MODE
2329   msgp = msg;
2330   msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds);
2331   for (i = 0; i < n_fds; i++)
2332     {
2333       static dbus_bool_t warned = FALSE;
2334       DBusSocket *s;
2335       DBusPollFD *fdp = &fds[i];
2336
2337       _dbus_handle_to_socket_unlocked(fdp->fd, &s);  
2338
2339       if (s->is_used == 0)
2340         {
2341           _dbus_warn ("no valid socket");
2342           warned = TRUE;
2343         }
2344
2345       if (fdp->events & _DBUS_POLLIN)
2346         msgp += sprintf (msgp, "R:%d ", s->fd);
2347
2348       if (fdp->events & _DBUS_POLLOUT)
2349         msgp += sprintf (msgp, "W:%d ", s->fd);
2350
2351       msgp += sprintf (msgp, "E:%d\n\t", s->fd);
2352
2353       // FIXME: more robust code for long  msg
2354       //        create on heap when msg[] becomes too small
2355       if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE)
2356         {
2357           _dbus_assert_not_reached ("buffer overflow in _dbus_poll");
2358         }
2359     }
2360
2361   msgp += sprintf (msgp, "\n");
2362   _dbus_verbose ("%s",msg);
2363 #endif
2364   for (i = 0; i < n_fds; i++)
2365     {
2366       DBusSocket *s;
2367       DBusPollFD *fdp = &fds[i];
2368
2369       _dbus_handle_to_socket_unlocked(fdp->fd, &s); 
2370
2371       if (s->is_used != 1)
2372         continue;
2373
2374       if (fdp->events & _DBUS_POLLIN)
2375         FD_SET (s->fd, &read_set);
2376
2377       if (fdp->events & _DBUS_POLLOUT)
2378         FD_SET (s->fd, &write_set);
2379
2380       FD_SET (s->fd, &err_set);
2381
2382       max_fd = MAX (max_fd, s->fd);
2383     }
2384
2385   _dbus_unlock_sockets();
2386
2387   tv.tv_sec = timeout_milliseconds / 1000;
2388   tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
2389
2390   ready = select (max_fd + 1, &read_set, &write_set, &err_set,
2391                   timeout_milliseconds < 0 ? NULL : &tv);
2392
2393   if (DBUS_SOCKET_API_RETURNS_ERROR (ready))
2394     {
2395       DBUS_SOCKET_SET_ERRNO ();
2396       if (errno != EWOULDBLOCK)
2397         _dbus_verbose ("select: failed: %s\n", _dbus_strerror (errno));
2398     }
2399   else if (ready == 0)
2400     _dbus_verbose ("select: = 0\n");
2401   else
2402     if (ready > 0)
2403       {
2404 #ifdef DBUS_ENABLE_VERBOSE_MODE
2405         msgp = msg;
2406         msgp += sprintf (msgp, "select: = %d:\n\t", ready);
2407         _dbus_lock_sockets();
2408         for (i = 0; i < n_fds; i++)
2409           {
2410             DBusSocket *s;
2411             DBusPollFD *fdp = &fds[i];
2412
2413             _dbus_handle_to_socket_unlocked(fdp->fd, &s); 
2414
2415             if (FD_ISSET (s->fd, &read_set))
2416               msgp += sprintf (msgp, "R:%d ", s->fd);
2417
2418             if (FD_ISSET (s->fd, &write_set))
2419               msgp += sprintf (msgp, "W:%d ", s->fd);
2420
2421             if (FD_ISSET (s->fd, &err_set))
2422               msgp += sprintf (msgp, "E:%d\n\t", s->fd);
2423           }
2424         msgp += sprintf (msgp, "\n");
2425         _dbus_verbose ("%s",msg);
2426 #endif
2427
2428         for (i = 0; i < n_fds; i++)
2429           {
2430             DBusSocket *s;
2431             DBusPollFD *fdp = &fds[i];
2432
2433             _dbus_handle_to_socket_unlocked(fdp->fd, &s); 
2434
2435             fdp->revents = 0;
2436
2437             if (FD_ISSET (s->fd, &read_set))
2438               fdp->revents |= _DBUS_POLLIN;
2439
2440             if (FD_ISSET (s->fd, &write_set))
2441               fdp->revents |= _DBUS_POLLOUT;
2442
2443             if (FD_ISSET (s->fd, &err_set))
2444               fdp->revents |= _DBUS_POLLERR;
2445           }
2446         _dbus_unlock_sockets();
2447       }
2448   return ready;
2449 }
2450 #else // ENABLE_DBUSSOCKET
2451
2452 int
2453 _dbus_poll (DBusPollFD *fds,
2454             int         n_fds,
2455             int         timeout_milliseconds)
2456 {
2457 #define DBUS_POLL_CHAR_BUFFER_SIZE 2000
2458   char msg[DBUS_POLL_CHAR_BUFFER_SIZE];
2459   char *msgp;
2460
2461   fd_set read_set, write_set, err_set;
2462   int max_fd = 0;
2463   int i;
2464   struct timeval tv;
2465   int ready;
2466
2467   FD_ZERO (&read_set);
2468   FD_ZERO (&write_set);
2469   FD_ZERO (&err_set);
2470
2471
2472 #ifdef DBUS_ENABLE_VERBOSE_MODE
2473   msgp = msg;
2474   msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds);
2475   for (i = 0; i < n_fds; i++)
2476     {
2477       static dbus_bool_t warned = FALSE;
2478       int fd;
2479       DBusPollFD *fdp = &fds[i];
2480       fd = fdp->fd;  
2481
2482
2483       if (fdp->events & _DBUS_POLLIN)
2484         msgp += sprintf (msgp, "R:%d ", fd);
2485
2486       if (fdp->events & _DBUS_POLLOUT)
2487         msgp += sprintf (msgp, "W:%d ", fd);
2488
2489       msgp += sprintf (msgp, "E:%d\n\t", fd);
2490
2491       // FIXME: more robust code for long  msg
2492       //        create on heap when msg[] becomes too small
2493       if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE)
2494         {
2495           _dbus_assert_not_reached ("buffer overflow in _dbus_poll");
2496         }
2497     }
2498
2499   msgp += sprintf (msgp, "\n");
2500   _dbus_verbose ("%s",msg);
2501 #endif
2502   for (i = 0; i < n_fds; i++)
2503     {
2504         int fd;
2505       DBusPollFD *fdp = &fds[i];
2506       fd = fdp->fd;  
2507
2508       if (fdp->events & _DBUS_POLLIN)
2509         FD_SET (fd, &read_set);
2510
2511       if (fdp->events & _DBUS_POLLOUT)
2512         FD_SET (fd, &write_set);
2513
2514       FD_SET (fd, &err_set);
2515
2516       max_fd = MAX (max_fd, fd);
2517     }
2518
2519
2520   tv.tv_sec = timeout_milliseconds / 1000;
2521   tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
2522
2523   ready = select (max_fd + 1, &read_set, &write_set, &err_set,
2524                   timeout_milliseconds < 0 ? NULL : &tv);
2525
2526   if (DBUS_SOCKET_API_RETURNS_ERROR (ready))
2527     {
2528       DBUS_SOCKET_SET_ERRNO ();
2529       if (errno != EWOULDBLOCK)
2530         _dbus_verbose ("select: failed: %s\n", _dbus_strerror (errno));
2531     }
2532   else if (ready == 0)
2533     _dbus_verbose ("select: = 0\n");
2534   else
2535     if (ready > 0)
2536       {
2537 #ifdef DBUS_ENABLE_VERBOSE_MODE
2538         msgp = msg;
2539         msgp += sprintf (msgp, "select: = %d:\n\t", ready);
2540
2541         for (i = 0; i < n_fds; i++)
2542           {
2543             int fd;
2544             DBusPollFD *fdp = &fds[i];
2545             fd = fdp->fd;  
2546
2547             if (FD_ISSET (fd, &read_set))
2548               msgp += sprintf (msgp, "R:%d ", fd);
2549
2550             if (FD_ISSET (fd, &write_set))
2551               msgp += sprintf (msgp, "W:%d ", fd);
2552
2553             if (FD_ISSET (fd, &err_set))
2554               msgp += sprintf (msgp, "E:%d\n\t", fd);
2555           }
2556         msgp += sprintf (msgp, "\n");
2557         _dbus_verbose ("%s",msg);
2558 #endif
2559
2560         for (i = 0; i < n_fds; i++)
2561           {
2562             int fd;
2563             DBusPollFD *fdp = &fds[i];
2564             fd = fdp->fd;  
2565
2566             fdp->revents = 0;
2567
2568             if (FD_ISSET (fd, &read_set))
2569               fdp->revents |= _DBUS_POLLIN;
2570
2571             if (FD_ISSET (fd, &write_set))
2572               fdp->revents |= _DBUS_POLLOUT;
2573
2574             if (FD_ISSET (fd, &err_set))
2575               fdp->revents |= _DBUS_POLLERR;
2576           }
2577       }
2578   return ready;
2579 }
2580
2581 #endif  //ENABLE_DBUSSOCKET
2582
2583 #endif  // USE_CHRIS_IMPL
2584
2585
2586 /************************************************************************
2587  
2588  error handling
2589  
2590  ************************************************************************/
2591
2592
2593 /**
2594  * Assigns an error name and message corresponding to a Win32 error
2595  * code to a DBusError. Does nothing if error is #NULL.
2596  *
2597  * @param error the error.
2598  * @param code the Win32 error code
2599  */
2600 void
2601 _dbus_win_set_error_from_win_error (DBusError *error,
2602                                     int        code)
2603 {
2604   char *msg;
2605
2606   /* As we want the English message, use the A API */
2607   FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
2608                   FORMAT_MESSAGE_IGNORE_INSERTS |
2609                   FORMAT_MESSAGE_FROM_SYSTEM,
2610                   NULL, code, MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US),
2611                   (LPTSTR) &msg, 0, NULL);
2612   if (msg)
2613     {
2614       char *msg_copy;
2615
2616       msg_copy = dbus_malloc (strlen (msg));
2617       strcpy (msg_copy, msg);
2618       LocalFree (msg);
2619
2620       dbus_set_error (error, "win32.error", "%s", msg_copy);
2621     }
2622   else
2623     dbus_set_error (error, "win32.error", "Unknown error code %d or FormatMessage failed", code);
2624 }
2625
2626 void
2627 _dbus_win_warn_win_error (const char *message,
2628                           int         code)
2629 {
2630   DBusError error;
2631
2632   dbus_error_init (&error);
2633   _dbus_win_set_error_from_win_error (&error, code);
2634   _dbus_warn ("%s: %s\n", message, error.message);
2635   dbus_error_free (&error);
2636 }
2637
2638 /**
2639  * A wrapper around strerror() because some platforms
2640  * may be lame and not have strerror().
2641  *
2642  * @param error_number errno.
2643  * @returns error description.
2644  */
2645 const char*
2646 _dbus_strerror (int error_number)
2647 {
2648 #ifdef DBUS_WINCE
2649   // TODO
2650   return "unknown";
2651 #else
2652   const char *msg;
2653
2654   switch (error_number)
2655     {
2656     case WSAEINTR:
2657       return "Interrupted function call";
2658     case WSAEACCES:
2659       return "Permission denied";
2660     case WSAEFAULT:
2661       return "Bad address";
2662     case WSAEINVAL:
2663       return "Invalid argument";
2664     case WSAEMFILE:
2665       return "Too many open files";
2666     case WSAEWOULDBLOCK:
2667       return "Resource temporarily unavailable";
2668     case WSAEINPROGRESS:
2669       return "Operation now in progress";
2670     case WSAEALREADY:
2671       return "Operation already in progress";
2672     case WSAENOTSOCK:
2673       return "Socket operation on nonsocket";
2674     case WSAEDESTADDRREQ:
2675       return "Destination address required";
2676     case WSAEMSGSIZE:
2677       return "Message too long";
2678     case WSAEPROTOTYPE:
2679       return "Protocol wrong type for socket";
2680     case WSAENOPROTOOPT:
2681       return "Bad protocol option";
2682     case WSAEPROTONOSUPPORT:
2683       return "Protocol not supported";
2684     case WSAESOCKTNOSUPPORT:
2685       return "Socket type not supported";
2686     case WSAEOPNOTSUPP:
2687       return "Operation not supported";
2688     case WSAEPFNOSUPPORT:
2689       return "Protocol family not supported";
2690     case WSAEAFNOSUPPORT:
2691       return "Address family not supported by protocol family";
2692     case WSAEADDRINUSE:
2693       return "Address already in use";
2694     case WSAEADDRNOTAVAIL:
2695       return "Cannot assign requested address";
2696     case WSAENETDOWN:
2697       return "Network is down";
2698     case WSAENETUNREACH:
2699       return "Network is unreachable";
2700     case WSAENETRESET:
2701       return "Network dropped connection on reset";
2702     case WSAECONNABORTED:
2703       return "Software caused connection abort";
2704     case WSAECONNRESET:
2705       return "Connection reset by peer";
2706     case WSAENOBUFS:
2707       return "No buffer space available";
2708     case WSAEISCONN:
2709       return "Socket is already connected";
2710     case WSAENOTCONN:
2711       return "Socket is not connected";
2712     case WSAESHUTDOWN:
2713       return "Cannot send after socket shutdown";
2714     case WSAETIMEDOUT:
2715       return "Connection timed out";
2716     case WSAECONNREFUSED:
2717       return "Connection refused";
2718     case WSAEHOSTDOWN:
2719       return "Host is down";
2720     case WSAEHOSTUNREACH:
2721       return "No route to host";
2722     case WSAEPROCLIM:
2723       return "Too many processes";
2724     case WSAEDISCON:
2725       return "Graceful shutdown in progress";
2726     case WSATYPE_NOT_FOUND:
2727       return "Class type not found";
2728     case WSAHOST_NOT_FOUND:
2729       return "Host not found";
2730     case WSATRY_AGAIN:
2731       return "Nonauthoritative host not found";
2732     case WSANO_RECOVERY:
2733       return "This is a nonrecoverable error";
2734     case WSANO_DATA:
2735       return "Valid name, no data record of requested type";
2736     case WSA_INVALID_HANDLE:
2737       return "Specified event object handle is invalid";
2738     case WSA_INVALID_PARAMETER:
2739       return "One or more parameters are invalid";
2740     case WSA_IO_INCOMPLETE:
2741       return "Overlapped I/O event object not in signaled state";
2742     case WSA_IO_PENDING:
2743       return "Overlapped operations will complete later";
2744     case WSA_NOT_ENOUGH_MEMORY:
2745       return "Insufficient memory available";
2746     case WSA_OPERATION_ABORTED:
2747       return "Overlapped operation aborted";
2748 #ifdef WSAINVALIDPROCTABLE
2749
2750     case WSAINVALIDPROCTABLE:
2751       return "Invalid procedure table from service provider";
2752 #endif
2753 #ifdef WSAINVALIDPROVIDER
2754
2755     case WSAINVALIDPROVIDER:
2756       return "Invalid service provider version number";
2757 #endif
2758 #ifdef WSAPROVIDERFAILEDINIT
2759
2760     case WSAPROVIDERFAILEDINIT:
2761       return "Unable to initialize a service provider";
2762 #endif
2763
2764     case WSASYSCALLFAILURE:
2765       return "System call failure";
2766     }
2767   msg = strerror (error_number);
2768   if (msg == NULL)
2769     msg = "unknown";
2770
2771   return msg;
2772 #endif //DBUS_WINCE
2773 }
2774
2775
2776
2777 /* lan manager error codes */
2778 const char*
2779 _dbus_lm_strerror(int error_number)
2780 {
2781 #ifdef DBUS_WINCE
2782   // TODO
2783   return "unknown";
2784 #else
2785   const char *msg;
2786   switch (error_number)
2787     {
2788     case NERR_NetNotStarted:
2789       return "The workstation driver is not installed.";
2790     case NERR_UnknownServer:
2791       return "The server could not be located.";
2792     case NERR_ShareMem:
2793       return "An internal error occurred. The network cannot access a shared memory segment.";
2794     case NERR_NoNetworkResource:
2795       return "A network resource shortage occurred.";
2796     case NERR_RemoteOnly:
2797       return "This operation is not supported on workstations.";
2798     case NERR_DevNotRedirected:
2799       return "The device is not connected.";
2800     case NERR_ServerNotStarted:
2801       return "The Server service is not started.";
2802     case NERR_ItemNotFound:
2803       return "The queue is empty.";
2804     case NERR_UnknownDevDir:
2805       return "The device or directory does not exist.";
2806     case NERR_RedirectedPath:
2807       return "The operation is invalid on a redirected resource.";
2808     case NERR_DuplicateShare:
2809       return "The name has already been shared.";
2810     case NERR_NoRoom:
2811       return "The server is currently out of the requested resource.";
2812     case NERR_TooManyItems:
2813       return "Requested addition of items exceeds the maximum allowed.";
2814     case NERR_InvalidMaxUsers:
2815       return "The Peer service supports only two simultaneous users.";
2816     case NERR_BufTooSmall:
2817       return "The API return buffer is too small.";
2818     case NERR_RemoteErr:
2819       return "A remote API error occurred.";
2820     case NERR_LanmanIniError:
2821       return "An error occurred when opening or reading the configuration file.";
2822     case NERR_NetworkError:
2823       return "A general network error occurred.";
2824     case NERR_WkstaInconsistentState:
2825       return "The Workstation service is in an inconsistent state. Restart the computer before restarting the Workstation service.";
2826     case NERR_WkstaNotStarted:
2827       return "The Workstation service has not been started.";
2828     case NERR_BrowserNotStarted:
2829       return "The requested information is not available.";
2830     case NERR_InternalError:
2831       return "An internal error occurred.";
2832     case NERR_BadTransactConfig:
2833       return "The server is not configured for transactions.";
2834     case NERR_InvalidAPI:
2835       return "The requested API is not supported on the remote server.";
2836     case NERR_BadEventName:
2837       return "The event name is invalid.";
2838     case NERR_DupNameReboot:
2839       return "The computer name already exists on the network. Change it and restart the computer.";
2840     case NERR_CfgCompNotFound:
2841       return "The specified component could not be found in the configuration information.";
2842     case NERR_CfgParamNotFound:
2843       return "The specified parameter could not be found in the configuration information.";
2844     case NERR_LineTooLong:
2845       return "A line in the configuration file is too long.";
2846     case NERR_QNotFound:
2847       return "The printer does not exist.";
2848     case NERR_JobNotFound:
2849       return "The print job does not exist.";
2850     case NERR_DestNotFound:
2851       return "The printer destination cannot be found.";
2852     case NERR_DestExists:
2853       return "The printer destination already exists.";
2854     case NERR_QExists:
2855       return "The printer queue already exists.";
2856     case NERR_QNoRoom:
2857       return "No more printers can be added.";
2858     case NERR_JobNoRoom:
2859       return "No more print jobs can be added.";
2860     case NERR_DestNoRoom:
2861       return "No more printer destinations can be added.";
2862     case NERR_DestIdle:
2863       return "This printer destination is idle and cannot accept control operations.";
2864     case NERR_DestInvalidOp:
2865       return "This printer destination request contains an invalid control function.";
2866     case NERR_ProcNoRespond:
2867       return "The print processor is not responding.";
2868     case NERR_SpoolerNotLoaded:
2869       return "The spooler is not running.";
2870     case NERR_DestInvalidState:
2871       return "This operation cannot be performed on the print destination in its current state.";
2872     case NERR_QInvalidState:
2873       return "This operation cannot be performed on the printer queue in its current state.";
2874     case NERR_JobInvalidState:
2875       return "This operation cannot be performed on the print job in its current state.";
2876     case NERR_SpoolNoMemory:
2877       return "A spooler memory allocation failure occurred.";
2878     case NERR_DriverNotFound:
2879       return "The device driver does not exist.";
2880     case NERR_DataTypeInvalid:
2881       return "The data type is not supported by the print processor.";
2882     case NERR_ProcNotFound:
2883       return "The print processor is not installed.";
2884     case NERR_ServiceTableLocked:
2885       return "The service database is locked.";
2886     case NERR_ServiceTableFull:
2887       return "The service table is full.";
2888     case NERR_ServiceInstalled:
2889       return "The requested service has already been started.";
2890     case NERR_ServiceEntryLocked:
2891       return "The service does not respond to control actions.";
2892     case NERR_ServiceNotInstalled:
2893       return "The service has not been started.";
2894     case NERR_BadServiceName:
2895       return "The service name is invalid.";
2896     case NERR_ServiceCtlTimeout:
2897       return "The service is not responding to the control function.";
2898     case NERR_ServiceCtlBusy:
2899       return "The service control is busy.";
2900     case NERR_BadServiceProgName:
2901       return "The configuration file contains an invalid service program name.";
2902     case NERR_ServiceNotCtrl:
2903       return "The service could not be controlled in its present state.";
2904     case NERR_ServiceKillProc:
2905       return "The service ended abnormally.";
2906     case NERR_ServiceCtlNotValid:
2907       return "The requested pause or stop is not valid for this service.";
2908     case NERR_NotInDispatchTbl:
2909       return "The service control dispatcher could not find the service name in the dispatch table.";
2910     case NERR_BadControlRecv:
2911       return "The service control dispatcher pipe read failed.";
2912     case NERR_ServiceNotStarting:
2913       return "A thread for the new service could not be created.";
2914     case NERR_AlreadyLoggedOn:
2915       return "This workstation is already logged on to the local-area network.";
2916     case NERR_NotLoggedOn:
2917       return "The workstation is not logged on to the local-area network.";
2918     case NERR_BadUsername:
2919       return "The user name or group name parameter is invalid.";
2920     case NERR_BadPassword:
2921       return "The password parameter is invalid.";
2922     case NERR_UnableToAddName_W:
2923       return "@W The logon processor did not add the message alias.";
2924     case NERR_UnableToAddName_F:
2925       return "The logon processor did not add the message alias.";
2926     case NERR_UnableToDelName_W:
2927       return "@W The logoff processor did not delete the message alias.";
2928     case NERR_UnableToDelName_F:
2929       return "The logoff processor did not delete the message alias.";
2930     case NERR_LogonsPaused:
2931       return "Network logons are paused.";
2932     case NERR_LogonServerConflict:
2933       return "A centralized logon-server conflict occurred.";
2934     case NERR_LogonNoUserPath:
2935       return "The server is configured without a valid user path.";
2936     case NERR_LogonScriptError:
2937       return "An error occurred while loading or running the logon script.";
2938     case NERR_StandaloneLogon:
2939       return "The logon server was not specified. Your computer will be logged on as STANDALONE.";
2940     case NERR_LogonServerNotFound:
2941       return "The logon server could not be found.";
2942     case NERR_LogonDomainExists:
2943       return "There is already a logon domain for this computer.";
2944     case NERR_NonValidatedLogon:
2945       return "The logon server could not validate the logon.";
2946     case NERR_ACFNotFound:
2947       return "The security database could not be found.";
2948     case NERR_GroupNotFound:
2949       return "The group name could not be found.";
2950     case NERR_UserNotFound:
2951       return "The user name could not be found.";
2952     case NERR_ResourceNotFound:
2953       return "The resource name could not be found.";
2954     case NERR_GroupExists:
2955       return "The group already exists.";
2956     case NERR_UserExists:
2957       return "The user account already exists.";
2958     case NERR_ResourceExists:
2959       return "The resource permission list already exists.";
2960     case NERR_NotPrimary:
2961       return "This operation is only allowed on the primary domain controller of the domain.";
2962     case NERR_ACFNotLoaded:
2963       return "The security database has not been started.";
2964     case NERR_ACFNoRoom:
2965       return "There are too many names in the user accounts database.";
2966     case NERR_ACFFileIOFail:
2967       return "A disk I/O failure occurred.";
2968     case NERR_ACFTooManyLists:
2969       return "The limit of 64 entries per resource was exceeded.";
2970     case NERR_UserLogon:
2971       return "Deleting a user with a session is not allowed.";
2972     case NERR_ACFNoParent:
2973       return "The parent directory could not be located.";
2974     case NERR_CanNotGrowSegment:
2975       return "Unable to add to the security database session cache segment.";
2976     case NERR_SpeGroupOp:
2977       return "This operation is not allowed on this special group.";
2978     case NERR_NotInCache:
2979       return "This user is not cached in user accounts database session cache.";
2980     case NERR_UserInGroup:
2981       return "The user already belongs to this group.";
2982     case NERR_UserNotInGroup:
2983       return "The user does not belong to this group.";
2984     case NERR_AccountUndefined:
2985       return "This user account is undefined.";
2986     case NERR_AccountExpired:
2987       return "This user account has expired.";
2988     case NERR_InvalidWorkstation:
2989       return "The user is not allowed to log on from this workstation.";
2990     case NERR_InvalidLogonHours:
2991       return "The user is not allowed to log on at this time.";
2992     case NERR_PasswordExpired:
2993       return "The password of this user has expired.";
2994     case NERR_PasswordCantChange:
2995       return "The password of this user cannot change.";
2996     case NERR_PasswordHistConflict:
2997       return "This password cannot be used now.";
2998     case NERR_PasswordTooShort:
2999       return "The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements.";
3000     case NERR_PasswordTooRecent:
3001       return "The password of this user is too recent to change.";
3002     case NERR_InvalidDatabase:
3003       return "The security database is corrupted.";
3004     case NERR_DatabaseUpToDate:
3005       return "No updates are necessary to this replicant network/local security database.";
3006     case NERR_SyncRequired:
3007       return "This replicant database is outdated; synchronization is required.";
3008     case NERR_UseNotFound:
3009       return "The network connection could not be found.";
3010     case NERR_BadAsgType:
3011       return "This asg_type is invalid.";
3012     case NERR_DeviceIsShared:
3013       return "This device is currently being shared.";
3014     case NERR_NoComputerName:
3015       return "The computer name could not be added as a message alias. The name may already exist on the network.";
3016     case NERR_MsgAlreadyStarted:
3017       return "The Messenger service is already started.";
3018     case NERR_MsgInitFailed:
3019       return "The Messenger service failed to start.";
3020     case NERR_NameNotFound:
3021       return "The message alias could not be found on the network.";
3022     case NERR_AlreadyForwarded:
3023       return "This message alias has already been forwarded.";
3024     case NERR_AddForwarded:
3025       return "This message alias has been added but is still forwarded.";
3026     case NERR_AlreadyExists:
3027       return "This message alias already exists locally.";
3028     case NERR_TooManyNames:
3029       return "The maximum number of added message aliases has been exceeded.";
3030     case NERR_DelComputerName:
3031       return "The computer name could not be deleted.";
3032     case NERR_LocalForward:
3033       return "Messages cannot be forwarded back to the same workstation.";
3034     case NERR_GrpMsgProcessor:
3035       return "An error occurred in the domain message processor.";
3036     case NERR_PausedRemote:
3037       return "The message was sent, but the recipient has paused the Messenger service.";
3038     case NERR_BadReceive:
3039       return "The message was sent but not received.";
3040     case NERR_NameInUse:
3041       return "The message alias is currently in use. Try again later.";
3042     case NERR_MsgNotStarted:
3043       return "The Messenger service has not been started.";
3044     case NERR_NotLocalName:
3045       return "The name is not on the local computer.";
3046     case NERR_NoForwardName:
3047       return "The forwarded message alias could not be found on the network.";
3048     case NERR_RemoteFull:
3049       return "The message alias table on the remote station is full.";
3050     case NERR_NameNotForwarded:
3051       return "Messages for this alias are not currently being forwarded.";
3052     case NERR_TruncatedBroadcast:
3053       return "The broadcast message was truncated.";
3054     case NERR_InvalidDevice:
3055       return "This is an invalid device name.";
3056     case NERR_WriteFault:
3057       return "A write fault occurred.";
3058     case NERR_DuplicateName:
3059       return "A duplicate message alias exists on the network.";
3060     case NERR_DeleteLater:
3061       return "@W This message alias will be deleted later.";
3062     case NERR_IncompleteDel:
3063       return "The message alias was not successfully deleted from all networks.";
3064     case NERR_MultipleNets:
3065       return "This operation is not supported on computers with multiple networks.";
3066     case NERR_NetNameNotFound:
3067       return "This shared resource does not exist.";
3068     case NERR_DeviceNotShared:
3069       return "This device is not shared.";
3070     case NERR_ClientNameNotFound:
3071       return "A session does not exist with that computer name.";
3072     case NERR_FileIdNotFound:
3073       return "There is not an open file with that identification number.";
3074     case NERR_ExecFailure:
3075       return "A failure occurred when executing a remote administration command.";
3076     case NERR_TmpFile:
3077       return "A failure occurred when opening a remote temporary file.";
3078     case NERR_TooMuchData:
3079       return "The data returned from a remote administration command has been truncated to 64K.";
3080     case NERR_DeviceShareConflict:
3081       return "This device cannot be shared as both a spooled and a non-spooled resource.";
3082     case NERR_BrowserTableIncomplete:
3083       return "The information in the list of servers may be incorrect.";
3084     case NERR_NotLocalDomain:
3085       return "The computer is not active in this domain.";
3086 #ifdef NERR_IsDfsShare
3087
3088     case NERR_IsDfsShare:
3089       return "The share must be removed from the Distributed File System before it can be deleted.";
3090 #endif
3091
3092     case NERR_DevInvalidOpCode:
3093       return "The operation is invalid for this device.";
3094     case NERR_DevNotFound:
3095       return "This device cannot be shared.";
3096     case NERR_DevNotOpen:
3097       return "This device was not open.";
3098     case NERR_BadQueueDevString:
3099       return "This device name list is invalid.";
3100     case NERR_BadQueuePriority:
3101       return "The queue priority is invalid.";
3102     case NERR_NoCommDevs:
3103       return "There are no shared communication devices.";
3104     case NERR_QueueNotFound:
3105       return "The queue you specified does not exist.";
3106     case NERR_BadDevString:
3107       return "This list of devices is invalid.";
3108     case NERR_BadDev:
3109       return "The requested device is invalid.";
3110     case NERR_InUseBySpooler:
3111       return "This device is already in use by the spooler.";
3112     case NERR_CommDevInUse:
3113       return "This device is already in use as a communication device.";
3114     case NERR_InvalidComputer:
3115       return "This computer name is invalid.";
3116     case NERR_MaxLenExceeded:
3117       return "The string and prefix specified are too long.";
3118     case NERR_BadComponent:
3119       return "This path component is invalid.";
3120     case NERR_CantType:
3121       return "Could not determine the type of input.";
3122     case NERR_TooManyEntries:
3123       return "The buffer for types is not big enough.";
3124     case NERR_ProfileFileTooBig:
3125       return "Profile files cannot exceed 64K.";
3126     case NERR_ProfileOffset:
3127       return "The start offset is out of range.";
3128     case NERR_ProfileCleanup:
3129       return "The system cannot delete current connections to network resources.";
3130     case NERR_ProfileUnknownCmd:
3131       return "The system was unable to parse the command line in this file.";
3132     case NERR_ProfileLoadErr:
3133       return "An error occurred while loading the profile file.";
3134     case NERR_ProfileSaveErr:
3135       return "@W Errors occurred while saving the profile file. The profile was partially saved.";
3136     case NERR_LogOverflow:
3137       return "Log file %1 is full.";
3138     case NERR_LogFileChanged:
3139       return "This log file has changed between reads.";
3140     case NERR_LogFileCorrupt:
3141       return "Log file %1 is corrupt.";
3142     case NERR_SourceIsDir:
3143       return "The source path cannot be a directory.";
3144     case NERR_BadSource:
3145       return "The source path is illegal.";
3146     case NERR_BadDest:
3147       return "The destination path is illegal.";
3148     case NERR_DifferentServers:
3149       return "The source and destination paths are on different servers.";
3150     case NERR_RunSrvPaused:
3151       return "The Run server you requested is paused.";
3152     case NERR_ErrCommRunSrv:
3153       return "An error occurred when communicating with a Run server.";
3154     case NERR_ErrorExecingGhost:
3155       return "An error occurred when starting a background process.";
3156     case NERR_ShareNotFound:
3157       return "The shared resource you are connected to could not be found.";
3158     case NERR_InvalidLana:
3159       return "The LAN adapter number is invalid.";
3160     case NERR_OpenFiles:
3161       return "There are open files on the connection.";
3162     case NERR_ActiveConns:
3163       return "Active connections still exist.";
3164     case NERR_BadPasswordCore:
3165       return "This share name or password is invalid.";
3166     case NERR_DevInUse:
3167       return "The device is being accessed by an active process.";
3168     case NERR_LocalDrive:
3169       return "The drive letter is in use locally.";
3170     case NERR_AlertExists:
3171       return "The specified client is already registered for the specified event.";
3172     case NERR_TooManyAlerts:
3173       return "The alert table is full.";
3174     case NERR_NoSuchAlert:
3175       return "An invalid or nonexistent alert name was raised.";
3176     case NERR_BadRecipient:
3177       return "The alert recipient is invalid.";
3178     case NERR_AcctLimitExceeded:
3179       return "A user's session with this server has been deleted.";
3180     case NERR_InvalidLogSeek:
3181       return "The log file does not contain the requested record number.";
3182     case NERR_BadUasConfig:
3183       return "The user accounts database is not configured correctly.";
3184     case NERR_InvalidUASOp:
3185       return "This operation is not permitted when the Netlogon service is running.";
3186     case NERR_LastAdmin:
3187       return "This operation is not allowed on the last administrative account.";
3188     case NERR_DCNotFound:
3189       return "Could not find domain controller for this domain.";
3190     case NERR_LogonTrackingError:
3191       return "Could not set logon information for this user.";
3192     case NERR_NetlogonNotStarted:
3193       return "The Netlogon service has not been started.";
3194     case NERR_CanNotGrowUASFile:
3195       return "Unable to add to the user accounts database.";
3196     case NERR_TimeDiffAtDC:
3197       return "This server's clock is not synchronized with the primary domain controller's clock.";
3198     case NERR_PasswordMismatch:
3199       return "A password mismatch has been detected.";
3200     case NERR_NoSuchServer:
3201       return "The server identification does not specify a valid server.";
3202     case NERR_NoSuchSession:
3203       return "The session identification does not specify a valid session.";
3204     case NERR_NoSuchConnection:
3205       return "The connection identification does not specify a valid connection.";
3206     case NERR_TooManyServers:
3207       return "There is no space for another entry in the table of available servers.";
3208     case NERR_TooManySessions:
3209       return "The server has reached the maximum number of sessions it supports.";
3210     case NERR_TooManyConnections:
3211       return "The server has reached the maximum number of connections it supports.";
3212     case NERR_TooManyFiles:
3213       return "The server cannot open more files because it has reached its maximum number.";
3214     case NERR_NoAlternateServers:
3215       return "There are no alternate servers registered on this server.";
3216     case NERR_TryDownLevel:
3217       return "Try down-level (remote admin protocol) version of API instead.";
3218     case NERR_UPSDriverNotStarted:
3219       return "The UPS driver could not be accessed by the UPS service.";
3220     case NERR_UPSInvalidConfig:
3221       return "The UPS service is not configured correctly.";
3222     case NERR_UPSInvalidCommPort:
3223       return "The UPS service could not access the specified Comm Port.";
3224     case NERR_UPSSignalAsserted:
3225       return "The UPS indicated a line fail or low battery situation. Service not started.";
3226     case NERR_UPSShutdownFailed:
3227       return "The UPS service failed to perform a system shut down.";
3228     case NERR_BadDosRetCode:
3229       return "The program below returned an MS-DOS error code:";
3230     case NERR_ProgNeedsExtraMem:
3231       return "The program below needs more memory:";
3232     case NERR_BadDosFunction:
3233       return "The program below called an unsupported MS-DOS function:";
3234     case NERR_RemoteBootFailed:
3235       return "The workstation failed to boot.";
3236     case NERR_BadFileCheckSum:
3237       return "The file below is corrupt.";
3238     case NERR_NoRplBootSystem:
3239       return "No loader is specified in the boot-block definition file.";
3240     case NERR_RplLoadrNetBiosErr:
3241       return "NetBIOS returned an error:      The NCB and SMB are dumped above.";
3242     case NERR_RplLoadrDiskErr:
3243       return "A disk I/O error occurred.";
3244     case NERR_ImageParamErr:
3245       return "Image parameter substitution failed.";
3246     case NERR_TooManyImageParams:
3247       return "Too many image parameters cross disk sector boundaries.";
3248     case NERR_NonDosFloppyUsed:
3249       return "The image was not generated from an MS-DOS diskette formatted with /S.";
3250     case NERR_RplBootRestart:
3251       return "Remote boot will be restarted later.";
3252     case NERR_RplSrvrCallFailed:
3253       return "The call to the Remoteboot server failed.";
3254     case NERR_CantConnectRplSrvr:
3255       return "Cannot connect to the Remoteboot server.";
3256     case NERR_CantOpenImageFile:
3257       return "Cannot open image file on the Remoteboot server.";
3258     case NERR_CallingRplSrvr:
3259       return "Connecting to the Remoteboot server...";
3260     case NERR_StartingRplBoot:
3261       return "Connecting to the Remoteboot server...";
3262     case NERR_RplBootServiceTerm:
3263       return "Remote boot service was stopped; check the error log for the cause of the problem.";
3264     case NERR_RplBootStartFailed:
3265       return "Remote boot startup failed; check the error log for the cause of the problem.";
3266     case NERR_RPL_CONNECTED:
3267       return "A second connection to a Remoteboot resource is not allowed.";
3268     case NERR_BrowserConfiguredToNotRun:
3269       return "The browser service was configured with MaintainServerList=No.";
3270     case NERR_RplNoAdaptersStarted:
3271       return "Service failed to start since none of the network adapters started with this service.";
3272     case NERR_RplBadRegistry:
3273       return "Service failed to start due to bad startup information in the registry.";
3274     case NERR_RplBadDatabase:
3275       return "Service failed to start because its database is absent or corrupt.";
3276     case NERR_RplRplfilesShare:
3277       return "Service failed to start because RPLFILES share is absent.";
3278     case NERR_RplNotRplServer:
3279       return "Service failed to start because RPLUSER group is absent.";
3280     case NERR_RplCannotEnum:
3281       return "Cannot enumerate service records.";
3282     case NERR_RplWkstaInfoCorrupted:
3283       return "Workstation record information has been corrupted.";
3284     case NERR_RplWkstaNotFound:
3285       return "Workstation record was not found.";
3286     case NERR_RplWkstaNameUnavailable:
3287       return "Workstation name is in use by some other workstation.";
3288     case NERR_RplProfileInfoCorrupted:
3289       return "Profile record information has been corrupted.";
3290     case NERR_RplProfileNotFound:
3291       return "Profile record was not found.";
3292     case NERR_RplProfileNameUnavailable:
3293       return "Profile name is in use by some other profile.";
3294     case NERR_RplProfileNotEmpty:
3295       return "There are workstations using this profile.";
3296     case NERR_RplConfigInfoCorrupted:
3297       return "Configuration record information has been corrupted.";
3298     case NERR_RplConfigNotFound:
3299       return "Configuration record was not found.";
3300     case NERR_RplAdapterInfoCorrupted:
3301       return "Adapter ID record information has been corrupted.";
3302     case NERR_RplInternal:
3303       return "An internal service error has occurred.";
3304     case NERR_RplVendorInfoCorrupted:
3305       return "Vendor ID record information has been corrupted.";
3306     case NERR_RplBootInfoCorrupted:
3307       return "Boot block record information has been corrupted.";
3308     case NERR_RplWkstaNeedsUserAcct:
3309       return "The user account for this workstation record is missing.";
3310     case NERR_RplNeedsRPLUSERAcct:
3311       return "The RPLUSER local group could not be found.";
3312     case NERR_RplBootNotFound:
3313       return "Boot block record was not found.";
3314     case NERR_RplIncompatibleProfile:
3315       return "Chosen profile is incompatible with this workstation.";
3316     case NERR_RplAdapterNameUnavailable:
3317       return "Chosen network adapter ID is in use by some other workstation.";
3318     case NERR_RplConfigNotEmpty:
3319       return "There are profiles using this configuration.";
3320     case NERR_RplBootInUse:
3321       return "There are workstations, profiles, or configurations using this boot block.";
3322     case NERR_RplBackupDatabase:
3323       return "Service failed to backup Remoteboot database.";
3324     case NERR_RplAdapterNotFound:
3325       return "Adapter record was not found.";
3326     case NERR_RplVendorNotFound:
3327       return "Vendor record was not found.";
3328     case NERR_RplVendorNameUnavailable:
3329       return "Vendor name is in use by some other vendor record.";
3330     case NERR_RplBootNameUnavailable:
3331       return "(boot name, vendor ID) is in use by some other boot block record.";
3332     case NERR_RplConfigNameUnavailable:
3333       return "Configuration name is in use by some other configuration.";
3334     case NERR_DfsInternalCorruption:
3335       return "The internal database maintained by the Dfs service is corrupt.";
3336     case NERR_DfsVolumeDataCorrupt:
3337       return "One of the records in the internal Dfs database is corrupt.";
3338     case NERR_DfsNoSuchVolume:
3339       return "There is no DFS name whose entry path matches the input Entry Path.";
3340     case NERR_DfsVolumeAlreadyExists:
3341       return "A root or link with the given name already exists.";
3342     case NERR_DfsAlreadyShared:
3343       return "The server share specified is already shared in the Dfs.";
3344     case NERR_DfsNoSuchShare:
3345       return "The indicated server share does not support the indicated DFS namespace.";
3346     case NERR_DfsNotALeafVolume:
3347       return "The operation is not valid on this portion of the namespace.";
3348     case NERR_DfsLeafVolume:
3349       return "The operation is not valid on this portion of the namespace.";
3350     case NERR_DfsVolumeHasMultipleServers:
3351       return "The operation is ambiguous because the link has multiple servers.";
3352     case NERR_DfsCantCreateJunctionPoint:
3353       return "Unable to create a link.";
3354     case NERR_DfsServerNotDfsAware:
3355       return "The server is not Dfs Aware.";
3356     case NERR_DfsBadRenamePath:
3357       return "The specified rename target path is invalid.";
3358     case NERR_DfsVolumeIsOffline:
3359       return "The specified DFS link is offline.";
3360     case NERR_DfsNoSuchServer:
3361       return "The specified server is not a server for this link.";
3362     case NERR_DfsCyclicalName:
3363       return "A cycle in the Dfs name was detected.";
3364     case NERR_DfsNotSupportedInServerDfs:
3365       return "The operation is not supported on a server-based Dfs.";
3366     case NERR_DfsDuplicateService:
3367       return "This link is already supported by the specified server-share.";
3368     case NERR_DfsCantRemoveLastServerShare:
3369       return "Can't remove the last server-share supporting this root or link.";
3370     case NERR_DfsVolumeIsInterDfs:
3371       return "The operation is not supported for an Inter-DFS link.";
3372     case NERR_DfsInconsistent:
3373       return "The internal state of the Dfs Service has become inconsistent.";
3374     case NERR_DfsServerUpgraded:
3375       return "The Dfs Service has been installed on the specified server.";
3376     case NERR_DfsDataIsIdentical:
3377       return "The Dfs data being reconciled is identical.";
3378     case NERR_DfsCantRemoveDfsRoot:
3379       return "The DFS root cannot be deleted. Uninstall DFS if required.";
3380     case NERR_DfsChildOrParentInDfs:
3381       return "A child or parent directory of the share is already in a Dfs.";
3382     case NERR_DfsInternalError:
3383       return "Dfs internal error.";
3384       /* the following are not defined in mingw */
3385 #if 0
3386
3387     case NERR_SetupAlreadyJoined:
3388       return "This machine is already joined to a domain.";
3389     case NERR_SetupNotJoined:
3390       return "This machine is not currently joined to a domain.";
3391     case NERR_SetupDomainController:
3392       return "This machine is a domain controller and cannot be unjoined from a domain.";
3393     case NERR_DefaultJoinRequired:
3394       return "The destination domain controller does not support creating machine accounts in OUs.";
3395     case NERR_InvalidWorkgroupName:
3396       return "The specified workgroup name is invalid.";
3397     case NERR_NameUsesIncompatibleCodePage:
3398       return "The specified computer name is incompatible with the default language used on the domain controller.";
3399     case NERR_ComputerAccountNotFound:
3400       return "The specified computer account could not be found.";
3401     case NERR_PersonalSku:
3402       return "This version of Windows cannot be joined to a domain.";
3403     case NERR_PasswordMustChange:
3404       return "The password must change at the next logon.";
3405     case NERR_AccountLockedOut:
3406       return "The account is locked out.";
3407     case NERR_PasswordTooLong:
3408       return "The password is too long.";
3409     case NERR_PasswordNotComplexEnough:
3410       return "The password does not meet the complexity policy.";
3411     case NERR_PasswordFilterError:
3412       return "The password does not meet the requirements of the password filter DLLs.";
3413 #endif
3414
3415     }
3416   msg = strerror (error_number);
3417   if (msg == NULL)
3418     msg = "unknown";
3419
3420   return msg;
3421 #endif //DBUS_WINCE
3422 }
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432 /******************************************************************************
3433  
3434 Original CVS version of dbus-sysdeps.c
3435  
3436 ******************************************************************************/
3437 /* -*- mode: C; c-file-style: "gnu" -*- */
3438 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-Bus implementation)
3439  * 
3440  * Copyright (C) 2002, 2003  Red Hat, Inc.
3441  * Copyright (C) 2003 CodeFactory AB
3442  * Copyright (C) 2005 Novell, Inc.
3443  *
3444  * Licensed under the Academic Free License version 2.1
3445  * 
3446  * This program is free software; you can redistribute it and/or modify
3447  * it under the terms of the GNU General Public License as published by
3448  * the Free Software Foundation; either version 2 of the License, or
3449  * (at your option) any later version.
3450  *
3451  * This program is distributed in the hope that it will be useful,
3452  * but WITHOUT ANY WARRANTY; without even the implied warranty of
3453  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3454  * GNU General Public License for more details.
3455  * 
3456  * You should have received a copy of the GNU General Public License
3457  * along with this program; if not, write to the Free Software
3458  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
3459  *
3460  */
3461
3462
3463 /**
3464  * @addtogroup DBusInternalsUtils
3465  * @{
3466  */
3467
3468 int _dbus_mkdir (const char *path,
3469                  mode_t mode)
3470 {
3471   return _mkdir(path);
3472 }
3473
3474 /**
3475  * Exit the process, returning the given value.
3476  *
3477  * @param code the exit code
3478  */
3479 void
3480 _dbus_exit (int code)
3481 {
3482   _exit (code);
3483 }
3484
3485 /**
3486  * Creates a socket and connects to a socket at the given host 
3487  * and port. The connection fd is returned, and is set up as
3488  * nonblocking.
3489  *
3490  * @param host the host name to connect to, NULL for loopback
3491  * @param port the prot to connect to
3492  * @param error return location for error code
3493  * @returns connection file descriptor or -1 on error
3494  */
3495 int
3496 _dbus_connect_tcp_socket (const char     *host,
3497                           dbus_uint32_t   port,
3498                           DBusError      *error)
3499 {
3500 #ifdef ENABLE_DBUSSOCKET
3501   DBusSocket s;
3502   int handle;
3503   struct sockaddr_in addr;
3504   struct hostent *he;
3505   struct in_addr *haddr;
3506   struct in_addr ina;
3507
3508   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3509
3510   _dbus_win_startup_winsock ();
3511
3512   s.fd = socket (AF_INET, SOCK_STREAM, 0);
3513
3514   if (DBUS_SOCKET_IS_INVALID (s.fd))
3515     {
3516       DBUS_SOCKET_SET_ERRNO ();
3517       dbus_set_error (error,
3518                       _dbus_error_from_errno (errno),
3519                       "Failed to create socket: %s",
3520                       _dbus_strerror (errno));
3521
3522       return -1;
3523     }
3524
3525   if (host == NULL)
3526     {
3527       host = "localhost";
3528       ina.s_addr = htonl (INADDR_LOOPBACK);
3529       haddr = &ina;
3530     }
3531
3532   he = gethostbyname (host);
3533   if (he == NULL)
3534     {
3535       DBUS_SOCKET_SET_ERRNO ();
3536       dbus_set_error (error,
3537                       _dbus_error_from_errno (errno),
3538                       "Failed to lookup hostname: %s",
3539                       host);
3540       DBUS_CLOSE_SOCKET (s.fd);
3541       return -1;
3542     }
3543
3544   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
3545
3546   _DBUS_ZERO (addr);
3547   memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
3548   addr.sin_family = AF_INET;
3549   addr.sin_port = htons (port);
3550
3551   if (DBUS_SOCKET_API_RETURNS_ERROR
3552       (connect (s.fd, (struct sockaddr*) &addr, sizeof (addr)) < 0))
3553     {
3554       DBUS_SOCKET_SET_ERRNO ();
3555       dbus_set_error (error,
3556                       _dbus_error_from_errno (errno),
3557                       "Failed to connect to socket %s:%d %s",
3558                       host, port, _dbus_strerror (errno));
3559
3560       DBUS_CLOSE_SOCKET (s.fd);
3561       s.fd = -1;
3562
3563       return -1;
3564     }
3565
3566   handle = _dbus_socket_to_handle (&s);
3567
3568   if (!_dbus_set_fd_nonblocking (handle, error))
3569     {
3570       _dbus_close_socket (handle, NULL);
3571       handle = -1;
3572
3573       return -1;
3574     }
3575
3576   return handle;
3577 #else
3578   int fd;
3579   struct sockaddr_in addr;
3580   struct hostent *he;
3581   struct in_addr *haddr;
3582   struct in_addr ina;
3583
3584   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3585
3586   _dbus_win_startup_winsock ();
3587
3588   fd = socket (AF_INET, SOCK_STREAM, 0);
3589
3590   if (DBUS_SOCKET_IS_INVALID (fd))
3591     {
3592       DBUS_SOCKET_SET_ERRNO ();
3593       dbus_set_error (error,
3594                       _dbus_error_from_errno (errno),
3595                       "Failed to create socket: %s",
3596                       _dbus_strerror (errno));
3597
3598       return -1;
3599     }
3600
3601   if (host == NULL)
3602     {
3603       host = "localhost";
3604       ina.s_addr = htonl (INADDR_LOOPBACK);
3605       haddr = &ina;
3606     }
3607
3608   he = gethostbyname (host);
3609   if (he == NULL)
3610     {
3611       DBUS_SOCKET_SET_ERRNO ();
3612       dbus_set_error (error,
3613                       _dbus_error_from_errno (errno),
3614                       "Failed to lookup hostname: %s",
3615                       host);
3616       DBUS_CLOSE_SOCKET (fd);
3617       return -1;
3618     }
3619
3620   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
3621
3622   _DBUS_ZERO (addr);
3623   memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
3624   addr.sin_family = AF_INET;
3625   addr.sin_port = htons (port);
3626
3627   if (DBUS_SOCKET_API_RETURNS_ERROR
3628       (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0))
3629     {
3630       DBUS_SOCKET_SET_ERRNO ();
3631       dbus_set_error (error,
3632                       _dbus_error_from_errno (errno),
3633                       "Failed to connect to socket %s:%d %s",
3634                       host, port, _dbus_strerror (errno));
3635
3636       DBUS_CLOSE_SOCKET (fd);
3637       fd = -1;
3638
3639       return -1;
3640     }
3641
3642   if (!_dbus_set_fd_nonblocking (fd, error))
3643     {
3644       _dbus_close_socket (fd, NULL);
3645       fd = -1;
3646
3647       return -1;
3648     }
3649
3650   return fd;
3651 #endif
3652 }
3653
3654 void
3655 _dbus_daemon_init(const char *host, dbus_uint32_t port);
3656 /**
3657  * Creates a socket and binds it to the given port,
3658  * then listens on the socket. The socket is
3659  * set to be nonblocking. 
3660  * In case of port=0 a random free port is used and 
3661  * returned in the port parameter. 
3662  *
3663  * @param host the interface to listen on, NULL for loopback, empty for any
3664  * @param port the port to listen on, if zero a free port will be used 
3665  * @param error return location for errors
3666  * @returns the listening file descriptor or -1 on error
3667  */
3668
3669 int
3670 _dbus_listen_tcp_socket (const char     *host,
3671                          dbus_uint32_t  *port,
3672                          dbus_bool_t     inaddr_any,
3673                          DBusError      *error)
3674 {
3675 #ifdef ENABLE_DBUSSOCKET
3676   DBusSocket slisten;
3677   int handle;
3678   struct sockaddr_in addr;
3679   struct hostent *he;
3680   struct in_addr *haddr;
3681   socklen_t len = (socklen_t) sizeof (struct sockaddr);
3682   struct in_addr ina;
3683
3684
3685   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3686
3687   _dbus_win_startup_winsock ();
3688
3689   slisten.fd = socket (AF_INET, SOCK_STREAM, 0);
3690
3691   if (DBUS_SOCKET_IS_INVALID (slisten.fd))
3692     {
3693       DBUS_SOCKET_SET_ERRNO ();
3694       dbus_set_error (error, _dbus_error_from_errno (errno),
3695                       "Failed to create socket \"%s:%d\": %s",
3696                       host, port, _dbus_strerror (errno));
3697       return -1;
3698     }
3699   if (host == NULL)
3700     {
3701       host = "localhost";
3702       ina.s_addr = htonl (INADDR_LOOPBACK);
3703       haddr = &ina;
3704     }
3705   else if (!host[0])
3706     {
3707       ina.s_addr = htonl (INADDR_ANY);
3708       haddr = &ina;
3709     }
3710   else
3711     {
3712       he = gethostbyname (host);
3713       if (he == NULL)
3714         {
3715           DBUS_SOCKET_SET_ERRNO ();
3716           dbus_set_error (error,
3717                           _dbus_error_from_errno (errno),
3718                           "Failed to lookup hostname: %s",
3719                           host);
3720           DBUS_CLOSE_SOCKET (slisten.fd);
3721           return -1;
3722         }
3723
3724       haddr = ((struct in_addr *) (he->h_addr_list)[0]);
3725     }
3726
3727   _DBUS_ZERO (addr);
3728   memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr));
3729   addr.sin_family = AF_INET;
3730   addr.sin_port = htons (*port);
3731
3732   if (bind (slisten.fd, (struct sockaddr*) &addr, sizeof (struct sockaddr)))
3733     {
3734       DBUS_SOCKET_SET_ERRNO ();
3735       dbus_set_error (error, _dbus_error_from_errno (errno),
3736                       "Failed to bind socket \"%s:%d\": %s",
3737                       host, *port, _dbus_strerror (errno));
3738       DBUS_CLOSE_SOCKET (slisten.fd);
3739       return -1;
3740     }
3741
3742   if (DBUS_SOCKET_API_RETURNS_ERROR (listen (slisten.fd, 30 /* backlog */)))
3743     {
3744       DBUS_SOCKET_SET_ERRNO ();
3745       dbus_set_error (error, _dbus_error_from_errno (errno),
3746                       "Failed to listen on socket \"%s:%d\": %s",
3747                       host, *port, _dbus_strerror (errno));
3748       DBUS_CLOSE_SOCKET (slisten.fd);
3749       return -1;
3750     }
3751
3752   getsockname(slisten.fd, (struct sockaddr*) &addr, &len);
3753   *port = (dbus_uint32_t) ntohs(addr.sin_port);
3754   
3755   _dbus_daemon_init(host, ntohs(addr.sin_port));
3756
3757   handle = _dbus_socket_to_handle (&slisten);
3758
3759   if (!_dbus_set_fd_nonblocking (handle, error))
3760     {
3761       _dbus_close_socket (handle, NULL);
3762       return -1;
3763     }
3764
3765   return handle;
3766 #else
3767   int fd;
3768   struct sockaddr_in addr;
3769   struct hostent *he;
3770   struct in_addr *haddr;
3771   socklen_t len = (socklen_t) sizeof (struct sockaddr);
3772   struct in_addr ina;
3773
3774
3775   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3776
3777   _dbus_win_startup_winsock ();
3778
3779   fd = socket (AF_INET, SOCK_STREAM, 0);
3780
3781   if (DBUS_SOCKET_IS_INVALID (fd))
3782     {
3783       DBUS_SOCKET_SET_ERRNO ();
3784       dbus_set_error (error, _dbus_error_from_errno (errno),
3785                       "Failed to create socket \"%s:%d\": %s",
3786                       host, port, _dbus_strerror (errno));
3787       return -1;
3788     }
3789   if (host == NULL)
3790     {
3791       host = "localhost";
3792       ina.s_addr = htonl (INADDR_LOOPBACK);
3793       haddr = &ina;
3794     }
3795   else if (!host[0])
3796     {
3797       ina.s_addr = htonl (INADDR_ANY);
3798       haddr = &ina;
3799     }
3800   else
3801     {
3802       he = gethostbyname (host);
3803       if (he == NULL)
3804         {
3805           DBUS_SOCKET_SET_ERRNO ();
3806           dbus_set_error (error,
3807                           _dbus_error_from_errno (errno),
3808                           "Failed to lookup hostname: %s",
3809                           host);
3810           DBUS_CLOSE_SOCKET (fd);
3811           return -1;
3812         }
3813
3814       haddr = ((struct in_addr *) (he->h_addr_list)[0]);
3815     }
3816
3817   _DBUS_ZERO (addr);
3818   memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr));
3819   addr.sin_family = AF_INET;
3820   addr.sin_port = htons (*port);
3821
3822   if (bind (fd, (struct sockaddr*) &addr, sizeof (struct sockaddr)))
3823     {
3824       DBUS_SOCKET_SET_ERRNO ();
3825       dbus_set_error (error, _dbus_error_from_errno (errno),
3826                       "Failed to bind socket \"%s:%d\": %s",
3827                       host, *port, _dbus_strerror (errno));
3828       DBUS_CLOSE_SOCKET (fd);
3829       return -1;
3830     }
3831
3832   if (DBUS_SOCKET_API_RETURNS_ERROR (listen (fd, 30 /* backlog */)))
3833     {
3834       DBUS_SOCKET_SET_ERRNO ();
3835       dbus_set_error (error, _dbus_error_from_errno (errno),
3836                       "Failed to listen on socket \"%s:%d\": %s",
3837                       host, *port, _dbus_strerror (errno));
3838       DBUS_CLOSE_SOCKET (fd);
3839       return -1;
3840     }
3841
3842   getsockname(fd, (struct sockaddr*) &addr, &len);
3843   *port = (dbus_uint32_t) ntohs(addr.sin_port);
3844   
3845   _dbus_daemon_init(host, ntohs(addr.sin_port));
3846
3847   if (!_dbus_set_fd_nonblocking (fd, error))
3848     {
3849       _dbus_close_socket (fd, NULL);
3850       return -1;
3851     }
3852
3853   return fd;
3854 #endif
3855 }
3856
3857
3858 /**
3859  * Accepts a connection on a listening socket.
3860  * Handles EINTR for you.
3861  *
3862  * @param listen_fd the listen file descriptor
3863  * @returns the connection fd of the client, or -1 on error
3864  */
3865 int
3866 _dbus_accept  (int listen_handle)
3867 {
3868 #ifdef ENABLE_DBUSSOCKET
3869   DBusSocket *slisten;
3870   DBusSocket sclient;
3871   struct sockaddr addr;
3872   socklen_t addrlen;
3873
3874   _dbus_handle_to_socket(listen_handle, &slisten);
3875
3876   addrlen = sizeof (addr);
3877
3878   //FIXME:  why do we not try it again on Windows?
3879 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
3880 retry:
3881 #endif
3882
3883   sclient.fd = accept (slisten->fd, &addr, &addrlen);
3884
3885   if (DBUS_SOCKET_IS_INVALID (sclient.fd))
3886     {
3887       DBUS_SOCKET_SET_ERRNO ();
3888 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
3889       if (errno == EINTR)
3890         goto retry;
3891 #else
3892       return -1;
3893 #endif
3894     }
3895
3896   return _dbus_socket_to_handle (&sclient);
3897 #else
3898   int fd;
3899   int sclient;
3900   struct sockaddr addr;
3901   socklen_t addrlen;
3902
3903   fd = listen_handle;
3904
3905   addrlen = sizeof (addr);
3906
3907   //FIXME:  why do we not try it again on Windows?
3908 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
3909 retry:
3910 #endif
3911
3912   sclient = accept (fd, &addr, &addrlen);
3913
3914   if (DBUS_SOCKET_IS_INVALID (sclient))
3915     {
3916       DBUS_SOCKET_SET_ERRNO ();
3917 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
3918       if (errno == EINTR)
3919         goto retry;
3920 #else
3921       return -1;
3922 #endif
3923     }
3924
3925   return sclient;
3926 #endif
3927 }
3928
3929
3930
3931
3932 dbus_bool_t
3933 _dbus_send_credentials_socket (int            handle,
3934                         DBusError      *error)
3935 {
3936 /* FIXME: for the session bus credentials shouldn't matter (?), but
3937  * for the system bus they are presumably essential. A rough outline
3938  * of a way to implement the credential transfer would be this:
3939  *
3940  * client waits to *read* a byte.
3941  *
3942  * server creates a named pipe with a random name, sends a byte
3943  * contining its length, and its name.
3944  *
3945  * client reads the name, connects to it (using Win32 API).
3946  *
3947  * server waits for connection to the named pipe, then calls
3948  * ImpersonateNamedPipeClient(), notes its now-current credentials,
3949  * calls RevertToSelf(), closes its handles to the named pipe, and
3950  * is done. (Maybe there is some other way to get the SID of a named
3951  * pipe client without having to use impersonation?)
3952  *
3953  * client closes its handles and is done.
3954  * 
3955  * Ralf: Why not sending credentials over the given this connection ?
3956  * Using named pipes makes it impossible to be connected from a unix client.  
3957  *
3958  */
3959   int bytes_written;
3960   DBusString buf; 
3961
3962   _dbus_string_init_const_len (&buf, "\0", 1);
3963 again:
3964   bytes_written = _dbus_write_socket (handle, &buf, 0, 1 );
3965
3966   if (bytes_written < 0 && errno == EINTR)
3967     goto again;
3968
3969   if (bytes_written < 0)
3970     {
3971       dbus_set_error (error, _dbus_error_from_errno (errno),
3972                       "Failed to write credentials byte: %s",
3973                      _dbus_strerror (errno));
3974       return FALSE;
3975     }
3976   else if (bytes_written == 0)
3977     {
3978       dbus_set_error (error, DBUS_ERROR_IO_ERROR,
3979                       "wrote zero bytes writing credentials byte");
3980       return FALSE;
3981     }
3982   else
3983     {
3984       _dbus_assert (bytes_written == 1);
3985       _dbus_verbose ("wrote 1 zero byte, credential sending isn't implemented yet\n");
3986       return TRUE;
3987     }
3988   return TRUE;
3989 }
3990
3991 /**
3992  * Gets the credentials of the current process.
3993  *
3994  * @param credentials credentials to fill in.
3995  */
3996 void
3997 _dbus_credentials_from_current_process (DBusCredentials *credentials)
3998 {
3999   credentials->pid = _dbus_getpid ();
4000   credentials->uid = _dbus_getuid ();
4001   credentials->gid = _dbus_getgid ();
4002 }
4003
4004 /**
4005  * Reads a single byte which must be nul (an error occurs otherwise),
4006  * and reads unix credentials if available. Fills in pid/uid/gid with
4007  * -1 if no credentials are available. Return value indicates whether
4008  * a byte was read, not whether we got valid credentials. On some
4009  * systems, such as Linux, reading/writing the byte isn't actually
4010  * required, but we do it anyway just to avoid multiple codepaths.
4011  * 
4012  * Fails if no byte is available, so you must select() first.
4013  *
4014  * The point of the byte is that on some systems we have to
4015  * use sendmsg()/recvmsg() to transmit credentials.
4016  *
4017  * @param client_fd the client file descriptor
4018  * @param credentials struct to fill with credentials of client
4019  * @param error location to store error code
4020  * @returns #TRUE on success
4021  */
4022 dbus_bool_t
4023 _dbus_read_credentials_socket  (int              handle,
4024                                      DBusCredentials *credentials,
4025                                      DBusError       *error)
4026 {
4027   int bytes_read;
4028   DBusString buf;
4029   _dbus_string_init(&buf);
4030
4031   bytes_read = _dbus_read_socket(handle, &buf, 1 );
4032   if (bytes_read > 0) 
4033     {
4034                 _dbus_verbose("got one zero byte from server");
4035     }
4036
4037   _dbus_string_free(&buf);
4038   _dbus_credentials_from_current_process (credentials);
4039   _dbus_verbose("FIXME: get faked credentials from current process");
4040
4041   return TRUE;
4042 }
4043
4044 /**
4045 * Checks to make sure the given directory is 
4046 * private to the user 
4047 *
4048 * @param dir the name of the directory
4049 * @param error error return
4050 * @returns #FALSE on failure
4051 **/
4052 dbus_bool_t
4053 _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
4054 {
4055   const char *directory;
4056   struct stat sb;
4057
4058   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
4059
4060   return TRUE;
4061 }
4062
4063 #ifdef ENABLE_DBUSUSERINFO
4064 dbus_bool_t
4065 fill_user_info (DBusUserInfo       *info,
4066                 dbus_uid_t          uid,
4067                 const DBusString   *username,
4068                 DBusError          *error)
4069 {
4070   const char *username_c;
4071
4072   /* exactly one of username/uid provided */
4073   _dbus_assert (username != NULL || uid != DBUS_UID_UNSET);
4074   _dbus_assert (username == NULL || uid == DBUS_UID_UNSET);
4075
4076   info->uid = DBUS_UID_UNSET;
4077   info->primary_gid = DBUS_GID_UNSET;
4078   info->group_ids = NULL;
4079   info->n_group_ids = 0;
4080   info->username = NULL;
4081   info->homedir = NULL;
4082
4083   if (username != NULL)
4084     username_c = _dbus_string_get_const_data (username);
4085   else
4086     username_c = NULL;
4087
4088   if (uid != DBUS_UID_UNSET)
4089     {
4090       if (!fill_win_user_info_from_uid (uid, info, error))
4091         {
4092           _dbus_verbose("%s after fill_win_user_info_from_uid\n",__FUNCTION__);
4093           return FALSE;
4094         }
4095     }
4096   else
4097     {
4098       wchar_t *wname = _dbus_win_utf8_to_utf16 (username_c, error);
4099
4100       if (!wname)
4101         return FALSE;
4102
4103       if (!fill_win_user_info_from_name (wname, info, error))
4104         {
4105           dbus_free (wname);
4106           return FALSE;
4107         }
4108       dbus_free (wname);
4109     }
4110
4111   return TRUE;
4112 }
4113 /**
4114  * Gets user info for the given user ID.
4115  *
4116  * @param info user info object to initialize
4117  * @param uid the user ID
4118  * @param error error return
4119  * @returns #TRUE on success
4120  */
4121 dbus_bool_t
4122 _dbus_user_info_fill_uid (DBusUserInfo *info,
4123                           dbus_uid_t    uid,
4124                           DBusError    *error)
4125 {
4126   return fill_user_info (info, uid,
4127                          NULL, error);
4128 }
4129
4130
4131 /**
4132  * Gets user info for the given username.
4133  *
4134  * @param info user info object to initialize
4135  * @param username the username
4136  * @param error error return
4137  * @returns #TRUE on success
4138  */
4139 dbus_bool_t
4140 _dbus_user_info_fill (DBusUserInfo     *info,
4141                       const DBusString *username,
4142                       DBusError        *error)
4143 {
4144   return fill_user_info (info, DBUS_UID_UNSET,
4145                          username, error);
4146 }
4147 #endif
4148
4149 /**
4150  * Appends the given filename to the given directory.
4151  *
4152  * @todo it might be cute to collapse multiple '/' such as "foo//"
4153  * concat "//bar"
4154  *
4155  * @param dir the directory name
4156  * @param next_component the filename
4157  * @returns #TRUE on success
4158  */
4159 dbus_bool_t
4160 _dbus_concat_dir_and_file (DBusString       *dir,
4161                            const DBusString *next_component)
4162 {
4163   dbus_bool_t dir_ends_in_slash;
4164   dbus_bool_t file_starts_with_slash;
4165
4166   if (_dbus_string_get_length (dir) == 0 ||
4167       _dbus_string_get_length (next_component) == 0)
4168     return TRUE;
4169
4170   dir_ends_in_slash =
4171     ('/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1) ||
4172      '\\' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1));
4173
4174   file_starts_with_slash =
4175     ('/' == _dbus_string_get_byte (next_component, 0) ||
4176      '\\' == _dbus_string_get_byte (next_component, 0));
4177
4178   if (dir_ends_in_slash && file_starts_with_slash)
4179     {
4180       _dbus_string_shorten (dir, 1);
4181     }
4182   else if (!(dir_ends_in_slash || file_starts_with_slash))
4183     {
4184       if (!_dbus_string_append_byte (dir, '\\'))
4185         return FALSE;
4186     }
4187
4188   return _dbus_string_copy (next_component, 0, dir,
4189                             _dbus_string_get_length (dir));
4190 }
4191
4192 /**
4193  * Adds the credentials of the current process to the
4194  * passed-in credentials object.
4195  *
4196  * @param credentials credentials to add to
4197  * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added
4198  */
4199
4200 dbus_bool_t
4201 _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
4202 {
4203   credentials->pid = _dbus_getpid();
4204   credentials->uid = _dbus_getuid();
4205   return TRUE;
4206 }
4207
4208
4209 /**
4210  * Gets a UID from a UID string.
4211  *
4212  * @param uid_str the UID in string form
4213  * @param uid UID to fill in
4214  * @returns #TRUE if successfully filled in UID
4215  */
4216 dbus_bool_t
4217 _dbus_parse_uid (const DBusString      *uid_str,
4218                  dbus_uid_t            *uid)
4219 {
4220   int end;
4221   long val;
4222   
4223   if (_dbus_string_get_length (uid_str) == 0)
4224     {
4225       _dbus_verbose ("UID string was zero length\n");
4226       return FALSE;
4227     }
4228
4229   val = -1;
4230   end = 0;
4231   if (!_dbus_string_parse_int (uid_str, 0, &val,
4232                                &end))
4233     {
4234       _dbus_verbose ("could not parse string as a UID\n");
4235       return FALSE;
4236     }
4237   
4238   if (end != _dbus_string_get_length (uid_str))
4239     {
4240       _dbus_verbose ("string contained trailing stuff after UID\n");
4241       return FALSE;
4242     }
4243
4244   *uid = val;
4245
4246   return TRUE;
4247 }
4248
4249 /**
4250  * Parses a desired identity provided from a client in the auth protocol.
4251  * On UNIX this means parsing a UID.
4252  *
4253  * @todo this is broken because it treats OOM and parse error
4254  * the same way. Needs a #DBusError.
4255  * 
4256  * @param credentials the credentials to add what we parse to
4257  * @param desired_identity the string to parse
4258  * @returns #TRUE if we successfully parsed something
4259  */
4260 dbus_bool_t
4261 _dbus_credentials_parse_and_add_desired (DBusCredentials  *credentials,
4262                                          const DBusString *desired_identity)
4263 {
4264   dbus_uid_t uid;
4265
4266   if (!_dbus_parse_uid (desired_identity, &uid))
4267     return FALSE;
4268
4269   if (!_dbus_credentials_add_unix_uid (credentials, uid))
4270     return FALSE;
4271
4272   return TRUE;
4273 }
4274
4275 /**
4276  * Adds the credentials corresponding to the given username.
4277  *
4278  * @param credentials credentials to fill in 
4279  * @param username the username
4280  * @returns #TRUE if the username existed and we got some credentials
4281  */
4282 dbus_bool_t
4283 _dbus_credentials_add_from_user (DBusCredentials  *credentials,
4284                                      const DBusString *username)
4285 {
4286   _dbus_verbose("_dbus_credentials_add_from_user is not implemented");
4287   return FALSE;
4288 }
4289
4290 /**
4291  * Append to the string the identity we would like to have when we
4292  * authenticate, on UNIX this is the current process UID and on
4293  * Windows something else, probably a Windows SID string.  No escaping
4294  * is required, that is done in dbus-auth.c. The username here
4295  * need not be anything human-readable, it can be the machine-readable
4296  * form i.e. a user id.
4297  * 
4298  * @param str the string to append to
4299  * @returns #FALSE on no memory
4300  */
4301 dbus_bool_t
4302 _dbus_append_user_from_current_process (DBusString *str)
4303 {
4304   return _dbus_string_append_uint (str,
4305                                    _dbus_getuid ());
4306 }
4307
4308 /**
4309  * Gets the home directory for the given user.
4310  *
4311  * @param username the username
4312  * @param homedir string to append home directory to
4313  * @returns #TRUE if user existed and we appended their homedir
4314  */
4315 dbus_bool_t
4316 _dbus_homedir_from_username (const DBusString *username,
4317                              DBusString       *homedir)
4318 {
4319     _dbus_string_append (homedir, "/");
4320     return TRUE;
4321 }
4322
4323 /**
4324  * Gets homedir of user owning current process.  The returned string
4325  * is valid until dbus_shutdown() is called.
4326  *
4327  * @param homedir place to store pointer to homedir
4328  * @returns #FALSE if no memory
4329  */
4330 dbus_bool_t
4331 _dbus_homedir_from_current_process (const DBusString  **homedir)
4332 {
4333   char *s = getenv("HOMEPATH");
4334   DBusString *dir=0;
4335   _dbus_string_init(dir);
4336   _dbus_string_append (dir, s);
4337   *homedir = dir;
4338   return TRUE;
4339 }
4340
4341 /**
4342  * Append to the string the identity we would like to have when we authenticate,
4343  * on UNIX this is the current process UID and on Windows something else.
4344  * No escaping is required, that is done in dbus-auth.c.
4345  * 
4346  * @param str the string to append to
4347  * @returns #FALSE on no memory
4348  */
4349 dbus_bool_t
4350 _dbus_append_desired_identity (DBusString *str)
4351 {
4352     /* FIXME: */
4353   return _dbus_string_append_uint (str,
4354                                    _dbus_getuid ());
4355 }
4356
4357 /**
4358  * Gets our process ID
4359  * @returns process ID
4360  */
4361 unsigned long
4362 _dbus_getpid (void)
4363 {
4364   return GetCurrentProcessId ();
4365 }
4366
4367 /** nanoseconds in a second */
4368 #define NANOSECONDS_PER_SECOND       1000000000
4369 /** microseconds in a second */
4370 #define MICROSECONDS_PER_SECOND      1000000
4371 /** milliseconds in a second */
4372 #define MILLISECONDS_PER_SECOND      1000
4373 /** nanoseconds in a millisecond */
4374 #define NANOSECONDS_PER_MILLISECOND  1000000
4375 /** microseconds in a millisecond */
4376 #define MICROSECONDS_PER_MILLISECOND 1000
4377
4378 /**
4379  * Sleeps the given number of milliseconds.
4380  * @param milliseconds number of milliseconds
4381  */
4382 void
4383 _dbus_sleep_milliseconds (int milliseconds)
4384 {
4385   Sleep (milliseconds);
4386 }
4387
4388
4389 /**
4390  * Get current time, as in gettimeofday().
4391  *
4392  * @param tv_sec return location for number of seconds
4393  * @param tv_usec return location for number of microseconds
4394  */
4395 void
4396 _dbus_get_current_time (long *tv_sec,
4397                         long *tv_usec)
4398 {
4399   FILETIME ft;
4400   dbus_uint64_t *time64 = (dbus_uint64_t *) &ft;
4401
4402   GetSystemTimeAsFileTime (&ft);
4403
4404   /* Convert from 100s of nanoseconds since 1601-01-01
4405   * to Unix epoch. Yes, this is Y2038 unsafe.
4406   */
4407   *time64 -= DBUS_INT64_CONSTANT (116444736000000000);
4408   *time64 /= 10;
4409
4410   if (tv_sec)
4411     *tv_sec = *time64 / 1000000;
4412
4413   if (tv_usec)
4414     *tv_usec = *time64 % 1000000;
4415 }
4416
4417
4418 /**
4419  * signal (SIGPIPE, SIG_IGN);
4420  */
4421 void
4422 _dbus_disable_sigpipe (void)
4423 {
4424     _dbus_verbose("FIXME: implement _dbus_disable_sigpipe (void)\n");
4425 }
4426
4427
4428 /**
4429  * Appends the contents of the given file to the string,
4430  * returning error code. At the moment, won't open a file
4431  * more than a megabyte in size.
4432  *
4433  * @param str the string to append to
4434  * @param filename filename to load
4435  * @param error place to set an error
4436  * @returns #FALSE if error was set
4437  */
4438 dbus_bool_t
4439 _dbus_file_get_contents (DBusString       *str,
4440                          const DBusString *filename,
4441                          DBusError        *error)
4442 {
4443   DBusFile file;
4444   struct stat sb;
4445   int orig_len;
4446   int total;
4447   const char *filename_c;
4448
4449   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
4450
4451   filename_c = _dbus_string_get_const_data (filename);
4452
4453   /* O_BINARY useful on Cygwin and Win32 */
4454   if (!_dbus_file_open (&file, filename_c, O_RDONLY | O_BINARY, -1))
4455     {
4456       dbus_set_error (error, _dbus_error_from_errno (errno),
4457                       "Failed to open \"%s\": %s",
4458                       filename_c,
4459                       _dbus_strerror (errno));
4460       return FALSE;
4461     }
4462
4463   if (!_dbus_fstat (&file, &sb))
4464     {
4465       dbus_set_error (error, _dbus_error_from_errno (errno),
4466                       "Failed to stat \"%s\": %s",
4467                       filename_c,
4468                       _dbus_strerror (errno));
4469
4470       _dbus_verbose ("fstat() failed: %s",
4471                      _dbus_strerror (errno));
4472
4473       _dbus_file_close (&file, NULL);
4474
4475       return FALSE;
4476     }
4477
4478   if (sb.st_size > _DBUS_ONE_MEGABYTE)
4479     {
4480       dbus_set_error (error, DBUS_ERROR_FAILED,
4481                       "File size %lu of \"%s\" is too large.",
4482                       (unsigned long) sb.st_size, filename_c);
4483       _dbus_file_close (&file, NULL);
4484       return FALSE;
4485     }
4486
4487   total = 0;
4488   orig_len = _dbus_string_get_length (str);
4489   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
4490     {
4491       int bytes_read;
4492
4493       while (total < (int) sb.st_size)
4494         {
4495           bytes_read = _dbus_file_read (&file, str,
4496                                         sb.st_size - total);
4497           if (bytes_read <= 0)
4498             {
4499               dbus_set_error (error, _dbus_error_from_errno (errno),
4500                               "Error reading \"%s\": %s",
4501                               filename_c,
4502                               _dbus_strerror (errno));
4503
4504               _dbus_verbose ("read() failed: %s",
4505                              _dbus_strerror (errno));
4506
4507               _dbus_file_close (&file, NULL);
4508               _dbus_string_set_length (str, orig_len);
4509               return FALSE;
4510             }
4511           else
4512             total += bytes_read;
4513         }
4514
4515       _dbus_file_close (&file, NULL);
4516       return TRUE;
4517     }
4518   else if (sb.st_size != 0)
4519     {
4520       _dbus_verbose ("Can only open regular files at the moment.\n");
4521       dbus_set_error (error, DBUS_ERROR_FAILED,
4522                       "\"%s\" is not a regular file",
4523                       filename_c);
4524       _dbus_file_close (&file, NULL);
4525       return FALSE;
4526     }
4527   else
4528     {
4529       _dbus_file_close (&file, NULL);
4530       return TRUE;
4531     }
4532 }
4533
4534 /**
4535  * Writes a string out to a file. If the file exists,
4536  * it will be atomically overwritten by the new data.
4537  *
4538  * @param str the string to write out
4539  * @param filename the file to save string to
4540  * @param error error to be filled in on failure
4541  * @returns #FALSE on failure
4542  */
4543 dbus_bool_t
4544 _dbus_string_save_to_file (const DBusString *str,
4545                            const DBusString *filename,
4546                            DBusError        *error)
4547 {
4548   DBusFile file;
4549   int bytes_to_write;
4550   const char *filename_c;
4551   DBusString tmp_filename;
4552   const char *tmp_filename_c;
4553   int total;
4554   dbus_bool_t need_unlink;
4555   dbus_bool_t retval;
4556
4557   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
4558
4559   retval = FALSE;
4560   need_unlink = FALSE;
4561
4562   if (!_dbus_string_init (&tmp_filename))
4563     {
4564       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
4565       return FALSE;
4566     }
4567
4568   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
4569     {
4570       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
4571       _dbus_string_free (&tmp_filename);
4572       return FALSE;
4573     }
4574
4575   if (!_dbus_string_append (&tmp_filename, "."))
4576     {
4577       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
4578       _dbus_string_free (&tmp_filename);
4579       return FALSE;
4580     }
4581
4582 #define N_TMP_FILENAME_RANDOM_BYTES 8
4583   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
4584     {
4585       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
4586       _dbus_string_free (&tmp_filename);
4587       return FALSE;
4588     }
4589
4590   filename_c = _dbus_string_get_const_data (filename);
4591   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
4592
4593   if (!_dbus_file_open (&file, tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
4594                         0600))
4595     {
4596       dbus_set_error (error, _dbus_error_from_errno (errno),
4597                       "Could not create %s: %s", tmp_filename_c,
4598                       _dbus_strerror (errno));
4599       goto out;
4600     }
4601
4602   need_unlink = TRUE;
4603
4604   total = 0;
4605   bytes_to_write = _dbus_string_get_length (str);
4606
4607   while (total < bytes_to_write)
4608     {
4609       int bytes_written;
4610
4611       bytes_written = _dbus_file_write (&file, str, total,
4612                                         bytes_to_write - total);
4613
4614       if (bytes_written <= 0)
4615         {
4616           dbus_set_error (error, _dbus_error_from_errno (errno),
4617                           "Could not write to %s: %s", tmp_filename_c,
4618                           _dbus_strerror (errno));
4619
4620           goto out;
4621         }
4622
4623       total += bytes_written;
4624     }
4625
4626   if (!_dbus_file_close (&file, NULL))
4627     {
4628       dbus_set_error (error, _dbus_error_from_errno (errno),
4629                       "Could not close file %s: %s",
4630                       tmp_filename_c, _dbus_strerror (errno));
4631
4632       goto out;
4633     }
4634
4635
4636   if ((unlink (filename_c) == -1 && errno != ENOENT) ||
4637        rename (tmp_filename_c, filename_c) < 0)
4638     {
4639       dbus_set_error (error, _dbus_error_from_errno (errno),
4640                       "Could not rename %s to %s: %s",
4641                       tmp_filename_c, filename_c,
4642                       _dbus_strerror (errno));
4643
4644       goto out;
4645     }
4646
4647   need_unlink = FALSE;
4648
4649   retval = TRUE;
4650
4651 out:
4652   /* close first, then unlink, to prevent ".nfs34234235" garbage
4653    * files
4654    */
4655
4656   if (_dbus_is_valid_file(&file))
4657     _dbus_file_close (&file, NULL);
4658
4659   if (need_unlink && unlink (tmp_filename_c) < 0)
4660     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
4661                    tmp_filename_c, _dbus_strerror (errno));
4662
4663   _dbus_string_free (&tmp_filename);
4664
4665   if (!retval)
4666     _DBUS_ASSERT_ERROR_IS_SET (error);
4667
4668   return retval;
4669 }
4670
4671
4672 /** Creates the given file, failing if the file already exists.
4673  *
4674  * @param filename the filename
4675  * @param error error location
4676  * @returns #TRUE if we created the file and it didn't exist
4677  */
4678 dbus_bool_t
4679 _dbus_create_file_exclusively (const DBusString *filename,
4680                                DBusError        *error)
4681 {
4682   DBusFile file;
4683   const char *filename_c;
4684
4685   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
4686
4687   filename_c = _dbus_string_get_const_data (filename);
4688
4689   if (!_dbus_file_open (&file, filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
4690                         0600))
4691     {
4692       dbus_set_error (error,
4693                       DBUS_ERROR_FAILED,
4694                       "Could not create file %s: %s\n",
4695                       filename_c,
4696                       _dbus_strerror (errno));
4697       return FALSE;
4698     }
4699
4700   if (!_dbus_file_close (&file, NULL))
4701     {
4702       dbus_set_error (error,
4703                       DBUS_ERROR_FAILED,
4704                       "Could not close file %s: %s\n",
4705                       filename_c,
4706                       _dbus_strerror (errno));
4707       return FALSE;
4708     }
4709
4710   return TRUE;
4711 }
4712
4713
4714 /**
4715  * Creates a directory; succeeds if the directory
4716  * is created or already existed.
4717  *
4718  * @param filename directory filename
4719  * @param error initialized error object
4720  * @returns #TRUE on success
4721  */
4722 dbus_bool_t
4723 _dbus_create_directory (const DBusString *filename,
4724                         DBusError        *error)
4725 {
4726   const char *filename_c;
4727
4728   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
4729
4730   filename_c = _dbus_string_get_const_data (filename);
4731
4732   if (_dbus_mkdir (filename_c, 0700) < 0)
4733     {
4734       if (errno == EEXIST)
4735         return TRUE;
4736
4737       dbus_set_error (error, DBUS_ERROR_FAILED,
4738                       "Failed to create directory %s: %s\n",
4739                       filename_c, _dbus_strerror (errno));
4740       return FALSE;
4741     }
4742   else
4743     return TRUE;
4744 }
4745
4746
4747 static void
4748 pseudorandom_generate_random_bytes_buffer (char *buffer,
4749     int   n_bytes)
4750 {
4751   long tv_usec;
4752   int i;
4753
4754   /* fall back to pseudorandom */
4755   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
4756                  n_bytes);
4757
4758   _dbus_get_current_time (NULL, &tv_usec);
4759   srand (tv_usec);
4760
4761   i = 0;
4762   while (i < n_bytes)
4763     {
4764       double r;
4765       unsigned int b;
4766
4767       r = rand ();
4768       b = (r / (double) RAND_MAX) * 255.0;
4769
4770       buffer[i] = b;
4771
4772       ++i;
4773     }
4774 }
4775
4776 static dbus_bool_t
4777 pseudorandom_generate_random_bytes (DBusString *str,
4778                                     int         n_bytes)
4779 {
4780   int old_len;
4781   char *p;
4782
4783   old_len = _dbus_string_get_length (str);
4784
4785   if (!_dbus_string_lengthen (str, n_bytes))
4786     return FALSE;
4787
4788   p = _dbus_string_get_data_len (str, old_len, n_bytes);
4789
4790   pseudorandom_generate_random_bytes_buffer (p, n_bytes);
4791
4792   return TRUE;
4793 }
4794
4795 /**
4796  * Gets the temporary files directory by inspecting the environment variables 
4797  * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned
4798  *
4799  * @returns location of temp directory
4800  */
4801 const char*
4802 _dbus_get_tmpdir(void)
4803 {
4804   static const char* tmpdir = NULL;
4805
4806   if (tmpdir == NULL)
4807     {
4808       if (tmpdir == NULL)
4809         tmpdir = getenv("TMP");
4810       if (tmpdir == NULL)
4811         tmpdir = getenv("TEMP");
4812       if (tmpdir == NULL)
4813         tmpdir = getenv("TMPDIR");
4814       if (tmpdir == NULL)
4815           tmpdir = "C:\\Temp";
4816     }
4817
4818   _dbus_assert(tmpdir != NULL);
4819
4820   return tmpdir;
4821 }
4822
4823
4824 /**
4825  * Deletes the given file.
4826  *
4827  * @param filename the filename
4828  * @param error error location
4829  * 
4830  * @returns #TRUE if unlink() succeeded
4831  */
4832 dbus_bool_t
4833 _dbus_delete_file (const DBusString *filename,
4834                    DBusError        *error)
4835 {
4836   const char *filename_c;
4837
4838   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
4839
4840   filename_c = _dbus_string_get_const_data (filename);
4841
4842   if (unlink (filename_c) < 0)
4843     {
4844       dbus_set_error (error, DBUS_ERROR_FAILED,
4845                       "Failed to delete file %s: %s\n",
4846                       filename_c, _dbus_strerror (errno));
4847       return FALSE;
4848     }
4849   else
4850     return TRUE;
4851 }
4852
4853 /**
4854  * Generates the given number of random bytes,
4855  * using the best mechanism we can come up with.
4856  *
4857  * @param str the string
4858  * @param n_bytes the number of random bytes to append to string
4859  * @returns #TRUE on success, #FALSE if no memory
4860  */
4861 dbus_bool_t
4862 _dbus_generate_random_bytes (DBusString *str,
4863                              int         n_bytes)
4864 {
4865   return pseudorandom_generate_random_bytes (str, n_bytes);
4866 }
4867
4868 #if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_BUILD_TESTS)
4869
4870 #ifdef _MSC_VER
4871 # ifdef BACKTRACES
4872 #  undef BACKTRACES
4873 # endif
4874 #else
4875 # define BACKTRACES
4876 #endif
4877
4878 #ifdef BACKTRACES
4879 /*
4880  * Backtrace Generator
4881  *
4882  * Copyright 2004 Eric Poech
4883  * Copyright 2004 Robert Shearman
4884  *
4885  * This library is free software; you can redistribute it and/or
4886  * modify it under the terms of the GNU Lesser General Public
4887  * License as published by the Free Software Foundation; either
4888  * version 2.1 of the License, or (at your option) any later version.
4889  *
4890  * This library is distributed in the hope that it will be useful,
4891  * but WITHOUT ANY WARRANTY; without even the implied warranty of
4892  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
4893  * Lesser General Public License for more details.
4894  *
4895  * You should have received a copy of the GNU Lesser General Public
4896  * License along with this library; if not, write to the Free Software
4897  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4898  */
4899
4900 #include <winver.h>
4901 #include <imagehlp.h>
4902 #include <stdio.h>
4903
4904 #define DPRINTF _dbus_warn
4905
4906 #ifdef _MSC_VER
4907 #define BOOL int
4908
4909 #define __i386__
4910 #endif
4911
4912 //#define MAKE_FUNCPTR(f) static typeof(f) * p##f
4913
4914 //MAKE_FUNCPTR(StackWalk);
4915 //MAKE_FUNCPTR(SymGetModuleBase);
4916 //MAKE_FUNCPTR(SymFunctionTableAccess);
4917 //MAKE_FUNCPTR(SymInitialize);
4918 //MAKE_FUNCPTR(SymGetSymFromAddr);
4919 //MAKE_FUNCPTR(SymGetModuleInfo);
4920 static BOOL (WINAPI *pStackWalk)(
4921   DWORD MachineType,
4922   HANDLE hProcess,
4923   HANDLE hThread,
4924   LPSTACKFRAME StackFrame,
4925   PVOID ContextRecord,
4926   PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
4927   PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
4928   PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
4929   PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
4930 );
4931 static DWORD (WINAPI *pSymGetModuleBase)(
4932   HANDLE hProcess,
4933   DWORD dwAddr
4934 );
4935 static PVOID  (WINAPI *pSymFunctionTableAccess)(
4936   HANDLE hProcess,
4937   DWORD AddrBase
4938 );
4939 static BOOL  (WINAPI *pSymInitialize)(
4940   HANDLE hProcess,
4941   PSTR UserSearchPath,
4942   BOOL fInvadeProcess
4943 );
4944 static BOOL  (WINAPI *pSymGetSymFromAddr)(
4945   HANDLE hProcess,
4946   DWORD Address,
4947   PDWORD Displacement,
4948   PIMAGEHLP_SYMBOL Symbol
4949 );
4950 static BOOL  (WINAPI *pSymGetModuleInfo)(
4951   HANDLE hProcess,
4952   DWORD dwAddr,
4953   PIMAGEHLP_MODULE ModuleInfo
4954 );
4955 static DWORD  (WINAPI *pSymSetOptions)(
4956   DWORD SymOptions
4957 );
4958
4959
4960 static BOOL init_backtrace()
4961 {
4962     HMODULE hmodDbgHelp = LoadLibraryA("dbghelp");
4963 /*
4964     #define GETFUNC(x) \
4965     p##x = (typeof(x)*)GetProcAddress(hmodDbgHelp, #x); \
4966     if (!p##x) \
4967     { \
4968         return FALSE; \
4969     }
4970     */
4971
4972
4973 //    GETFUNC(StackWalk);
4974 //    GETFUNC(SymGetModuleBase);
4975 //    GETFUNC(SymFunctionTableAccess);
4976 //    GETFUNC(SymInitialize);
4977 //    GETFUNC(SymGetSymFromAddr);
4978 //    GETFUNC(SymGetModuleInfo);
4979
4980 #define FUNC(x) #x
4981
4982       pStackWalk = (BOOL  (WINAPI *)(
4983 DWORD MachineType,
4984 HANDLE hProcess,
4985 HANDLE hThread,
4986 LPSTACKFRAME StackFrame,
4987 PVOID ContextRecord,
4988 PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
4989 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
4990 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
4991 PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
4992 ))GetProcAddress (hmodDbgHelp, FUNC(StackWalk));
4993     pSymGetModuleBase=(DWORD  (WINAPI *)(
4994   HANDLE hProcess,
4995   DWORD dwAddr
4996 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase));
4997     pSymFunctionTableAccess=(PVOID  (WINAPI *)(
4998   HANDLE hProcess,
4999   DWORD AddrBase
5000 ))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess));
5001     pSymInitialize = (BOOL  (WINAPI *)(
5002   HANDLE hProcess,
5003   PSTR UserSearchPath,
5004   BOOL fInvadeProcess
5005 ))GetProcAddress (hmodDbgHelp, FUNC(SymInitialize));
5006     pSymGetSymFromAddr = (BOOL  (WINAPI *)(
5007   HANDLE hProcess,
5008   DWORD Address,
5009   PDWORD Displacement,
5010   PIMAGEHLP_SYMBOL Symbol
5011 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetSymFromAddr));
5012     pSymGetModuleInfo = (BOOL  (WINAPI *)(
5013   HANDLE hProcess,
5014   DWORD dwAddr,
5015   PIMAGEHLP_MODULE ModuleInfo
5016 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleInfo));
5017 pSymSetOptions = (DWORD  (WINAPI *)(
5018 DWORD SymOptions
5019 ))GetProcAddress (hmodDbgHelp, FUNC(SymSetOptions));
5020
5021
5022     pSymSetOptions(SYMOPT_UNDNAME);
5023
5024     pSymInitialize(GetCurrentProcess(), NULL, TRUE);
5025
5026     return TRUE;
5027 }
5028
5029 static void dump_backtrace_for_thread(HANDLE hThread)
5030 {
5031     STACKFRAME sf;
5032     CONTEXT context;
5033     DWORD dwImageType;
5034
5035     if (!pStackWalk)
5036         if (!init_backtrace())
5037             return;
5038
5039     /* can't use this function for current thread as GetThreadContext
5040      * doesn't support getting context from current thread */
5041     if (hThread == GetCurrentThread())
5042         return;
5043
5044     DPRINTF("Backtrace:\n");
5045
5046     memset(&context, 0, sizeof(context));
5047     context.ContextFlags = CONTEXT_FULL;
5048
5049     SuspendThread(hThread);
5050
5051     if (!GetThreadContext(hThread, &context))
5052     {
5053         DPRINTF("Couldn't get thread context (error %ld)\n", GetLastError());
5054         ResumeThread(hThread);
5055         return;
5056     }
5057
5058     memset(&sf, 0, sizeof(sf));
5059
5060 #ifdef __i386__
5061     sf.AddrFrame.Offset = context.Ebp;
5062     sf.AddrFrame.Mode = AddrModeFlat;
5063     sf.AddrPC.Offset = context.Eip;
5064     sf.AddrPC.Mode = AddrModeFlat;
5065     dwImageType = IMAGE_FILE_MACHINE_I386;
5066 #else
5067 # error You need to fill in the STACKFRAME structure for your architecture
5068 #endif
5069
5070     while (pStackWalk(dwImageType, GetCurrentProcess(),
5071                      hThread, &sf, &context, NULL, pSymFunctionTableAccess,
5072                      pSymGetModuleBase, NULL))
5073     {
5074         BYTE buffer[256];
5075         IMAGEHLP_SYMBOL * pSymbol = (IMAGEHLP_SYMBOL *)buffer;
5076         DWORD dwDisplacement;
5077
5078         pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
5079         pSymbol->MaxNameLength = sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL) + 1;
5080
5081         if (!pSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
5082                                 &dwDisplacement, pSymbol))
5083         {
5084             IMAGEHLP_MODULE ModuleInfo;
5085             ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
5086
5087             if (!pSymGetModuleInfo(GetCurrentProcess(), sf.AddrPC.Offset,
5088                                    &ModuleInfo))
5089                 DPRINTF("1\t%p\n", (void*)sf.AddrPC.Offset);
5090             else
5091                 DPRINTF("2\t%s+0x%lx\n", ModuleInfo.ImageName,
5092                     sf.AddrPC.Offset - ModuleInfo.BaseOfImage);
5093         }
5094         else if (dwDisplacement)
5095             DPRINTF("3\t%s+0x%lx\n", pSymbol->Name, dwDisplacement);
5096         else
5097             DPRINTF("4\t%s\n", pSymbol->Name);
5098     }
5099
5100     ResumeThread(hThread);
5101 }
5102
5103 static DWORD WINAPI dump_thread_proc(LPVOID lpParameter)
5104 {
5105     dump_backtrace_for_thread((HANDLE)lpParameter);
5106     return 0;
5107 }
5108
5109 /* cannot get valid context from current thread, so we have to execute
5110  * backtrace from another thread */
5111 static void dump_backtrace()
5112 {
5113     HANDLE hCurrentThread;
5114     HANDLE hThread;
5115     DWORD dwThreadId;
5116     DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
5117         GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
5118     hThread = CreateThread(NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread,
5119         0, &dwThreadId);
5120     WaitForSingleObject(hThread, INFINITE);
5121     CloseHandle(hThread);
5122     CloseHandle(hCurrentThread);
5123 }
5124
5125 void _dbus_print_backtrace(void)
5126 {
5127   init_backtrace();
5128   dump_backtrace();
5129 }
5130 #else
5131 void _dbus_print_backtrace(void)
5132 {
5133   _dbus_verbose ("  D-Bus not compiled with backtrace support\n");
5134 }
5135 #endif
5136
5137 static dbus_uint32_t fromAscii(char ascii)
5138 {
5139     if(ascii >= '0' && ascii <= '9')
5140         return ascii - '0';
5141     if(ascii >= 'A' && ascii <= 'F')
5142         return ascii - 'A' + 10;
5143     if(ascii >= 'a' && ascii <= 'f')
5144         return ascii - 'a' + 10;
5145     return 0;    
5146 }
5147
5148 dbus_bool_t _dbus_read_local_machine_uuid   (DBusGUID         *machine_id,
5149                                              dbus_bool_t       create_if_not_found,
5150                                              DBusError        *error)
5151 {
5152 #ifdef DBUS_WINCE
5153         return TRUE;
5154   // TODO
5155 #else
5156     HW_PROFILE_INFOA info;
5157     char *lpc = &info.szHwProfileGuid[0];
5158     dbus_uint32_t u;
5159
5160     //  the hw-profile guid lives long enough
5161     if(!GetCurrentHwProfileA(&info))
5162       {
5163         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); // FIXME
5164         return FALSE;  
5165       }
5166
5167     // Form: {12340001-4980-1920-6788-123456789012}
5168     lpc++;
5169     // 12340001
5170     u = ((fromAscii(lpc[0]) <<  0) |
5171          (fromAscii(lpc[1]) <<  4) |
5172          (fromAscii(lpc[2]) <<  8) |
5173          (fromAscii(lpc[3]) << 12) |
5174          (fromAscii(lpc[4]) << 16) |
5175          (fromAscii(lpc[5]) << 20) |
5176          (fromAscii(lpc[6]) << 24) |
5177          (fromAscii(lpc[7]) << 28));
5178     machine_id->as_uint32s[0] = u;
5179
5180     lpc += 9;
5181     // 4980-1920
5182     u = ((fromAscii(lpc[0]) <<  0) |
5183          (fromAscii(lpc[1]) <<  4) |
5184          (fromAscii(lpc[2]) <<  8) |
5185          (fromAscii(lpc[3]) << 12) |
5186          (fromAscii(lpc[5]) << 16) |
5187          (fromAscii(lpc[6]) << 20) |
5188          (fromAscii(lpc[7]) << 24) |
5189          (fromAscii(lpc[8]) << 28));
5190     machine_id->as_uint32s[1] = u;
5191     
5192     lpc += 10;
5193     // 6788-1234
5194     u = ((fromAscii(lpc[0]) <<  0) |
5195          (fromAscii(lpc[1]) <<  4) |
5196          (fromAscii(lpc[2]) <<  8) |
5197          (fromAscii(lpc[3]) << 12) |
5198          (fromAscii(lpc[5]) << 16) |
5199          (fromAscii(lpc[6]) << 20) |
5200          (fromAscii(lpc[7]) << 24) |
5201          (fromAscii(lpc[8]) << 28));
5202     machine_id->as_uint32s[2] = u;
5203     
5204     lpc += 9;
5205     // 56789012
5206     u = ((fromAscii(lpc[0]) <<  0) |
5207          (fromAscii(lpc[1]) <<  4) |
5208          (fromAscii(lpc[2]) <<  8) |
5209          (fromAscii(lpc[3]) << 12) |
5210          (fromAscii(lpc[4]) << 16) |
5211          (fromAscii(lpc[5]) << 20) |
5212          (fromAscii(lpc[6]) << 24) |
5213          (fromAscii(lpc[7]) << 28));
5214     machine_id->as_uint32s[3] = u;
5215 #endif
5216     return TRUE;
5217 }
5218
5219 static
5220 HANDLE _dbus_global_lock (const char *mutexname)
5221 {
5222   HANDLE mutex;
5223   DWORD gotMutex;
5224
5225   mutex = CreateMutex( NULL, FALSE, mutexname );
5226   if( !mutex )
5227     {
5228       return FALSE;
5229     }
5230
5231    gotMutex = WaitForSingleObject( mutex, INFINITE );
5232    switch( gotMutex )
5233      {
5234        case WAIT_ABANDONED:
5235                ReleaseMutex (mutex);
5236                CloseHandle (mutex);
5237                return 0;
5238        case WAIT_FAILED:
5239        case WAIT_TIMEOUT:
5240                return 0;
5241      }
5242
5243    return mutex;
5244 }
5245
5246 static
5247 void _dbus_global_unlock (HANDLE mutex)
5248 {
5249   ReleaseMutex (mutex);
5250   CloseHandle (mutex); 
5251 }
5252
5253 // for proper cleanup in dbus-daemon
5254 static HANDLE hDBusDaemonMutex = NULL;
5255 static HANDLE hDBusSharedMem = NULL;
5256 // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs
5257 static const char *cUniqueDBusInitMutex = "UniqueDBusInitMutex";
5258 // sync _dbus_get_autolaunch_address
5259 static const char *cDBusAutolaunchMutex = "DBusAutolaunchMutex";
5260 // mutex to determine if dbus-daemon is already started (per user)
5261 static const char *cDBusDaemonMutex = "DBusDaemonMutex";
5262 // named shm for dbus adress info (per user)
5263 static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo";
5264
5265 void
5266 _dbus_daemon_init(const char *host, dbus_uint32_t port)
5267 {
5268   HANDLE lock;
5269   const char *adr = NULL;
5270   char szUserName[64];
5271   DWORD dwUserNameSize = sizeof(szUserName);
5272   char szDBusDaemonMutex[128];
5273   char szDBusDaemonAddressInfo[128];
5274   char szAddress[128];
5275
5276   _dbus_assert(host);
5277   _dbus_assert(port);
5278
5279   _snprintf(szAddress, sizeof(szAddress) - 1, "tcp:host=%s,port=%d", host, port);
5280
5281   _dbus_assert( GetUserName(szUserName, &dwUserNameSize) != 0);
5282   _snprintf(szDBusDaemonMutex, sizeof(szDBusDaemonMutex) - 1, "%s:%s",
5283             cDBusDaemonMutex, szUserName);
5284   _snprintf(szDBusDaemonAddressInfo, sizeof(szDBusDaemonAddressInfo) - 1, "%s:%s",
5285             cDBusDaemonAddressInfo, szUserName);
5286
5287   // before _dbus_global_lock to keep correct lock/release order
5288   hDBusDaemonMutex = CreateMutex( NULL, FALSE, szDBusDaemonMutex );
5289
5290   _dbus_assert(WaitForSingleObject( hDBusDaemonMutex, 1000 ) == WAIT_OBJECT_0);
5291
5292   // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs
5293   lock = _dbus_global_lock( cUniqueDBusInitMutex );
5294
5295   // create shm
5296   hDBusSharedMem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
5297                                       0, strlen( szAddress ) + 1, szDBusDaemonAddressInfo );
5298   _dbus_assert( hDBusSharedMem );
5299
5300   adr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 );
5301
5302   _dbus_assert( adr );
5303
5304   strcpy(adr, szAddress);
5305
5306   // cleanup
5307   UnmapViewOfFile( adr );
5308
5309   _dbus_global_unlock( lock );
5310 }
5311
5312 void
5313 _dbus_daemon_release()
5314 {
5315   HANDLE lock;
5316
5317   // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs
5318   lock = _dbus_global_lock( cUniqueDBusInitMutex );
5319
5320   CloseHandle( hDBusSharedMem );
5321
5322   hDBusSharedMem = NULL;
5323
5324   ReleaseMutex( hDBusDaemonMutex );
5325
5326   CloseHandle( hDBusDaemonMutex );
5327
5328   hDBusDaemonMutex = NULL;
5329
5330   _dbus_global_unlock( lock );
5331 }
5332
5333 static dbus_bool_t
5334 _dbus_get_autolaunch_shm(DBusString *adress)
5335 {
5336   HANDLE sharedMem;
5337   const char *adr;
5338   char szUserName[64];
5339   DWORD dwUserNameSize = sizeof(szUserName);
5340   char szDBusDaemonAddressInfo[128];
5341
5342   if( !GetUserName(szUserName, &dwUserNameSize) )
5343       return FALSE;
5344   _snprintf(szDBusDaemonAddressInfo, sizeof(szDBusDaemonAddressInfo) - 1, "%s:%s",
5345             cDBusDaemonAddressInfo, szUserName);
5346
5347   // read shm
5348   do {
5349       // we know that dbus-daemon is available, so we wait until shm is available
5350       sharedMem = OpenFileMapping( FILE_MAP_READ, FALSE, szDBusDaemonAddressInfo );
5351       if( sharedMem == 0 )
5352           Sleep( 100 );
5353   } while( sharedMem == 0 );
5354
5355   if( sharedMem == 0 )
5356       return FALSE;
5357
5358   adr = MapViewOfFile( sharedMem, FILE_MAP_READ, 0, 0, 0 );
5359
5360   if( adr == 0 )
5361       return FALSE;
5362
5363   _dbus_string_init( adress );
5364
5365   _dbus_string_append( adress, adr ); 
5366
5367   // cleanup
5368   UnmapViewOfFile( adr );
5369
5370   CloseHandle( sharedMem );
5371
5372   return TRUE;
5373 }
5374
5375 static dbus_bool_t
5376 _dbus_daemon_already_runs (DBusString *adress)
5377 {
5378   HANDLE lock;
5379   HANDLE daemon;
5380   dbus_bool_t bRet = TRUE;
5381   char szUserName[64];
5382   DWORD dwUserNameSize = sizeof(szUserName);
5383   char szDBusDaemonMutex[128];
5384
5385   // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs
5386   lock = _dbus_global_lock( cUniqueDBusInitMutex );
5387
5388   if( !GetUserName(szUserName, &dwUserNameSize) )
5389       return FALSE;
5390   _snprintf(szDBusDaemonMutex, sizeof(szDBusDaemonMutex) - 1, "%s:%s",
5391             cDBusDaemonMutex, szUserName);
5392
5393   // do checks
5394   daemon = CreateMutex( NULL, FALSE, szDBusDaemonMutex );
5395   if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT)
5396     {
5397       ReleaseMutex (daemon);
5398       CloseHandle (daemon);
5399
5400       _dbus_global_unlock( lock );
5401       return FALSE;
5402     }
5403
5404   // read shm
5405   bRet = _dbus_get_autolaunch_shm( adress );
5406
5407   // cleanup
5408   CloseHandle ( daemon );
5409
5410   _dbus_global_unlock( lock );
5411
5412   return bRet;
5413 }
5414
5415 dbus_bool_t
5416 _dbus_get_autolaunch_address (DBusString *address, 
5417                               DBusError *error)
5418 {
5419   HANDLE mutex;
5420   STARTUPINFOA si;
5421   PROCESS_INFORMATION pi;
5422   dbus_bool_t retval = FALSE;
5423   LPSTR lpFile;
5424   char dbus_exe_path[MAX_PATH];
5425   char dbus_args[MAX_PATH * 2];
5426
5427   mutex = _dbus_global_lock ( cDBusAutolaunchMutex );
5428
5429   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
5430
5431   if (_dbus_daemon_already_runs(address))
5432     {
5433         printf("dbus daemon already exists\n");
5434         retval = TRUE;
5435         goto out;
5436     }
5437
5438   if (!SearchPathA(NULL, "dbus-daemon.exe", NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile))
5439     {
5440       printf ("could not find dbus-daemon executable\n");
5441       goto out;
5442     }
5443
5444   // Create process
5445   ZeroMemory( &si, sizeof(si) );
5446   si.cb = sizeof(si);
5447   ZeroMemory( &pi, sizeof(pi) );
5448
5449   _snprintf(dbus_args, sizeof(dbus_args) - 1, "\"%s\" %s", dbus_exe_path,  " --session");
5450
5451 //  argv[i] = "--config-file=bus\\session.conf";
5452   printf("create process \"%s\" %s\n", dbus_exe_path, dbus_args);
5453   if(CreateProcessA(dbus_exe_path, dbus_args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
5454     {
5455       retval = TRUE;
5456
5457       // Wait until started (see _dbus_get_autolaunch_shm())
5458       WaitForInputIdle(pi.hProcess, INFINITE);
5459
5460       retval = _dbus_get_autolaunch_shm( address );
5461     } else {
5462       retval = FALSE;
5463     }
5464   
5465 out:
5466   if (retval)
5467     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
5468   else
5469     _DBUS_ASSERT_ERROR_IS_SET (error);
5470   
5471   _dbus_global_unlock (mutex);
5472
5473   return retval;
5474  }
5475
5476
5477 /** Makes the file readable by every user in the system.
5478  *
5479  * @param filename the filename
5480  * @param error error location
5481  * @returns #TRUE if the file's permissions could be changed.
5482  */
5483 dbus_bool_t
5484 _dbus_make_file_world_readable(const DBusString *filename,
5485                                DBusError *error)
5486 {
5487   // TODO
5488   return TRUE;
5489 }
5490
5491
5492 #define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
5493
5494
5495 /**
5496  * Returns the standard directories for a session bus to look for service 
5497  * activation files 
5498  *
5499  * On Windows this should be data directories:
5500  *
5501  * %CommonProgramFiles%/dbus
5502  *
5503  * and
5504  *
5505  * DBUS_DATADIR
5506  *
5507  * @param dirs the directory list we are returning
5508  * @returns #FALSE on OOM 
5509  */
5510
5511 dbus_bool_t 
5512 _dbus_get_standard_session_servicedirs (DBusList **dirs)
5513 {
5514   const char *common_progs;
5515   DBusString servicedir_path;
5516
5517   if (!_dbus_string_init (&servicedir_path))
5518     return FALSE;
5519
5520   if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR _DBUS_PATH_SEPARATOR))
5521         goto oom;
5522
5523   common_progs = _dbus_getenv ("CommonProgramFiles");
5524
5525   if (common_progs != NULL)
5526     {
5527       if (!_dbus_string_append (&servicedir_path, common_progs))
5528         goto oom;
5529
5530       if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR))
5531         goto oom;
5532     }
5533
5534   if (!_dbus_split_paths_and_append (&servicedir_path, 
5535                                DBUS_STANDARD_SESSION_SERVICEDIR, 
5536                                dirs))
5537     goto oom;
5538
5539   _dbus_string_free (&servicedir_path);  
5540   return TRUE;
5541
5542  oom:
5543   _dbus_string_free (&servicedir_path);
5544   return FALSE;
5545 }
5546
5547 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
5548
5549 /**
5550  * Atomically increments an integer
5551  *
5552  * @param atomic pointer to the integer to increment
5553  * @returns the value before incrementing
5554  *
5555  */
5556 dbus_int32_t
5557 _dbus_atomic_inc (DBusAtomic *atomic)
5558 {
5559   // +/- 1 is needed here!
5560   return InterlockedIncrement (&atomic->value) - 1;
5561 }
5562
5563 /**
5564  * Atomically decrement an integer
5565  *
5566  * @param atomic pointer to the integer to decrement
5567  * @returns the value before decrementing
5568  *
5569  */
5570 dbus_int32_t
5571 _dbus_atomic_dec (DBusAtomic *atomic)
5572 {
5573   // +/- 1 is needed here!
5574   return InterlockedDecrement (&atomic->value) + 1;
5575 }
5576
5577 #endif /* asserts or tests enabled */
5578
5579 /**
5580  * Called when the bus daemon is signaled to reload its configuration; any
5581  * caches should be nuked. Of course any caches that need explicit reload
5582  * are probably broken, but c'est la vie.
5583  *
5584  * 
5585  */
5586 void
5587 _dbus_flush_caches (void)
5588 {
5589
5590 }
5591
5592 dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid)
5593 {
5594     return TRUE;
5595 }
5596
5597 /**
5598  * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently
5599  * for Winsock so is abstracted)
5600  *
5601  * @returns #TRUE if errno == EAGAIN or errno == EWOULDBLOCK
5602  */
5603 dbus_bool_t
5604 _dbus_get_is_errno_eagain_or_ewouldblock (void)
5605 {
5606   return errno == EAGAIN || errno == EWOULDBLOCK;
5607 }
5608
5609 /**
5610  * return the absolute path of the dbus installation 
5611  *
5612  * @param s buffer for installation path
5613  * @param len length of buffer
5614  * @returns #FALSE on failure
5615  */
5616 dbus_bool_t 
5617 _dbus_get_install_root(char *s, int len)
5618 {
5619   char *p = NULL;
5620   int ret = GetModuleFileName(NULL,s,len);
5621   if ( ret == 0 
5622     || ret == len && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5623     {
5624       *s = '\0';
5625       return FALSE;
5626     }
5627   else if ((p = strstr(s,"\\bin\\")))
5628     {
5629       *(p+1)= '\0';
5630       return TRUE;
5631     }
5632   else
5633     {
5634       *s = '\0';
5635       return FALSE;
5636     }
5637 }
5638
5639 /** 
5640   find config file either from installation or build root according to 
5641   the following path layout 
5642     install-root/
5643       bin/dbus-daemon[d].exe
5644       etc/<config-file>.conf 
5645
5646     build-root/
5647       bin/dbus-daemon[d].exe
5648       bus/<config-file>.conf 
5649 */
5650 dbus_bool_t 
5651 _dbus_get_config_file_name(DBusString *config_file, char *s)
5652 {
5653   char path[MAX_PATH*2];
5654   int path_size = sizeof(path);
5655
5656   if (!_dbus_get_install_root(path,path_size))
5657     return FALSE;
5658
5659   strcat_s(path,path_size,"etc\\");
5660   strcat_s(path,path_size,s);
5661   if (_dbus_file_exists(path)) 
5662     {
5663       // find path from executable 
5664       if (!_dbus_string_append (config_file, path))
5665         return FALSE;
5666     }
5667   else 
5668     {
5669       if (!_dbus_get_install_root(path,path_size))
5670         return FALSE;
5671       strcat_s(path,path_size,"bus\\");
5672       strcat_s(path,path_size,s);
5673   
5674       if (_dbus_file_exists(path)) 
5675         {
5676           if (!_dbus_string_append (config_file, path))
5677             return FALSE;
5678         }
5679     }
5680   return TRUE;
5681 }    
5682
5683 /**
5684  * Append the absolute path of the system.conf file
5685  * (there is no system bus on Windows so this can just
5686  * return FALSE and print a warning or something)
5687  * 
5688  * @param str the string to append to
5689  * @returns #FALSE if no memory
5690  */
5691 dbus_bool_t
5692 _dbus_append_system_config_file (DBusString *str)
5693 {
5694   return _dbus_get_config_file_name(str, "system.conf");
5695 }
5696
5697 /**
5698  * Append the absolute path of the session.conf file.
5699  * 
5700  * @param str the string to append to
5701  * @returns #FALSE if no memory
5702  */
5703 dbus_bool_t
5704 _dbus_append_session_config_file (DBusString *str)
5705 {
5706   return _dbus_get_config_file_name(str, "session.conf");
5707 }
5708
5709 /**
5710  * Appends the directory in which a keyring for the given credentials
5711  * should be stored.  The credentials should have either a Windows or
5712  * UNIX user in them.  The directory should be an absolute path.
5713  *
5714  * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably
5715  * be something else, since the dotfile convention is not normal on Windows.
5716  * 
5717  * @param directory string to append directory to
5718  * @param credentials credentials the directory should be for
5719  *  
5720  * @returns #FALSE on no memory
5721  */
5722 dbus_bool_t
5723 _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
5724                                                 DBusCredentials *credentials)
5725 {
5726   DBusString homedir;
5727   DBusString dotdir;
5728   dbus_uid_t uid;
5729   const char *homepath;
5730
5731   _dbus_assert (credentials != NULL);
5732   _dbus_assert (!_dbus_credentials_are_anonymous (credentials));
5733   
5734   if (!_dbus_string_init (&homedir))
5735     return FALSE;
5736
5737   homepath = _dbus_getenv("HOMEPATH");
5738   if (homepath != NULL && *homepath != '\0')
5739     {
5740       _dbus_string_append(&homedir,homepath);
5741     }
5742   
5743 #ifdef DBUS_BUILD_TESTS
5744   {
5745     const char *override;
5746     
5747     override = _dbus_getenv ("DBUS_TEST_HOMEDIR");
5748     if (override != NULL && *override != '\0')
5749       {
5750         _dbus_string_set_length (&homedir, 0);
5751         if (!_dbus_string_append (&homedir, override))
5752           goto failed;
5753
5754         _dbus_verbose ("Using fake homedir for testing: %s\n",
5755                        _dbus_string_get_const_data (&homedir));
5756       }
5757     else
5758       {
5759         static dbus_bool_t already_warned = FALSE;
5760         if (!already_warned)
5761           {
5762             _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n");
5763             already_warned = TRUE;
5764           }
5765       }
5766   }
5767 #endif
5768
5769   _dbus_string_init_const (&dotdir, ".dbus-keyrings");
5770   if (!_dbus_concat_dir_and_file (&homedir,
5771                                   &dotdir))
5772     goto failed;
5773   
5774   if (!_dbus_string_copy (&homedir, 0,
5775                           directory, _dbus_string_get_length (directory))) {
5776     goto failed;
5777   }
5778
5779   _dbus_string_free (&homedir);
5780   return TRUE;
5781   
5782  failed: 
5783   _dbus_string_free (&homedir);
5784   return FALSE;
5785 }
5786
5787 /** @} end of sysdeps-win */
5788 /* tests in dbus-sysdeps-util.c */