diff options
| author | Ralf Habacker <ralf.habacker@freenet.de> | 2007-03-03 17:25:54 +0000 | 
|---|---|---|
| committer | Ralf Habacker <ralf.habacker@freenet.de> | 2007-03-03 17:25:54 +0000 | 
| commit | 70bfc74e54ac8a9a93885710cd8350d1a58b3406 (patch) | |
| tree | bb5d76cff584faee079c95775872f484fb63f19b | |
| parent | 36ebfd411b358fb4797d31d23f945e8f6844d15a (diff) | |
* dbus/*-win.*,bus/*-win.*: added win32 platform related
files. These files are only added to the cmake build system.
The missing dbus-win32.patch file will be added later.
| -rw-r--r-- | ChangeLog | 6 | ||||
| -rw-r--r-- | dbus/dbus-sockets-win.h | 78 | ||||
| -rw-r--r-- | dbus/dbus-spawn-win.c | 832 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-util-win.c | 821 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-win.c | 5178 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-win.h | 174 | 
6 files changed, 7089 insertions, 0 deletions
| @@ -1,5 +1,11 @@  2007-03-03  Ralf Habacker  <ralf.habacker@freenet.de> +	* dbus/*-win.*,bus/*-win.*: added win32 platform related +	files. These files are only added to the cmake build system.   +	The missing dbus-win32.patch file will be added later.  + +2007-03-03  Ralf Habacker  <ralf.habacker@freenet.de> +  	* cmake: new directory, contains cmake build support.  	See http://www.cmake.org for more informations.  	Currently only unix will be buildable because some  diff --git a/dbus/dbus-sockets-win.h b/dbus/dbus-sockets-win.h new file mode 100644 index 00000000..86767419 --- /dev/null +++ b/dbus/dbus-sockets-win.h @@ -0,0 +1,78 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sockets.h Wrappers around socket features (internal to D-BUS implementation) + *  + * Copyright (C) 2005 Novell, Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#ifndef DBUS_SOCKETS_H +#define DBUS_SOCKETS_H + +#if defined(DBUS_WIN) || defined(DBUS_WINCE) + + + +#ifndef STRICT +#define STRICT +#include <winsock2.h> +#undef STRICT +#endif +#include <winsock2.h> + +#undef interface + +#include <errno.h> + +/* Make use of the fact that the WSAE* error codes don't + * overlap with errno E* codes. Wrapper functions store + * the return value from WSAGetLastError() in errno. + */ +#if defined(EPROTONOSUPPORT) || \ +    defined(EAFNOSUPPORT) || \ +    defined(EWOULDBLOCK) +#error This does not look like Win32 and the Microsoft C library +#endif + +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define EWOULDBLOCK WSAEWOULDBLOCK + +#define DBUS_SOCKET_IS_INVALID(s) ((SOCKET)(s) == INVALID_SOCKET) +#define DBUS_SOCKET_API_RETURNS_ERROR(n) ((n) == SOCKET_ERROR) +#define DBUS_SOCKET_SET_ERRNO() errno = WSAGetLastError() + +#define DBUS_CLOSE_SOCKET(s) closesocket(s) + +#else + +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> + +#define DBUS_SOCKET_IS_INVALID(s) ((s) < 0) +#define DBUS_SOCKET_API_RETURNS_ERROR(n) ((n) < 0) +#define DBUS_SOCKET_SET_ERRNO()	/* empty */ + +#define DBUS_CLOSE_SOCKET(s) close(s) + +#endif /* !Win32 */ + +#endif /* DBUS_SOCKETS_H */ diff --git a/dbus/dbus-spawn-win.c b/dbus/dbus-spawn-win.c new file mode 100644 index 00000000..7d93300f --- /dev/null +++ b/dbus/dbus-spawn-win.c @@ -0,0 +1,832 @@ +#include "config.h" + +#if !defined(DBUS_ENABLE_VERBOSE_MODE) || defined(_MSC_VER) +#define PING() +#else +#define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr) +#endif + +#include <stdio.h> +#ifdef DBUS_WINCE +#include <process.h> +#endif + +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-spawn-win32.c Wrapper around g_spawn + *  + * Copyright (C) 2002, 2003, 2004  Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2005 Novell, Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ +#include "dbus-spawn.h" +#include "dbus-sysdeps.h" +#include "dbus-sysdeps-win.h" +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-protocol.h" + +#define WIN32_LEAN_AND_MEAN +//#define STRICT +//#include <windows.h> +//#undef STRICT +#include <winsock2.h> +#undef interface + +#include <stdlib.h> + +#include <process.h> + +/** + * Babysitter implementation details + */ +struct DBusBabysitter +  { +    int refcount; + +    HANDLE start_sync_event; +#ifdef DBUS_BUILD_TESTS + +    HANDLE end_sync_event; +#endif + +    char *executable; +    DBusSpawnChildSetupFunc child_setup; +    void *user_data; + +    int argc; +    char **argv; +    char **envp; + +    HANDLE child_handle; +    int socket_to_babysitter;	/* Connection to the babysitter thread */ +    int socket_to_main; + +    DBusWatchList *watches; +    DBusWatch *sitter_watch; + +    dbus_bool_t have_spawn_errno; +    int spawn_errno; +    dbus_bool_t have_child_status; +    int child_status; +  }; + +static DBusBabysitter* +_dbus_babysitter_new (void) +{ +  DBusBabysitter *sitter; + +  sitter = dbus_new0 (DBusBabysitter, 1); +  if (sitter == NULL) +    return NULL; + +  sitter->refcount = 1; + +  sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); +  if (sitter->start_sync_event == NULL) +    { +      _dbus_babysitter_unref (sitter); +      return NULL; +    } + +#ifdef DBUS_BUILD_TESTS +  sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); +  if (sitter->end_sync_event == NULL) +    { +      _dbus_babysitter_unref (sitter); +      return NULL; +    } +#endif + +  sitter->child_handle = NULL; + +  sitter->socket_to_babysitter = sitter->socket_to_main = -1; + +  sitter->argc = 0; +  sitter->argv = NULL; +  sitter->envp = NULL; + +  sitter->watches = _dbus_watch_list_new (); +  if (sitter->watches == NULL) +    { +      _dbus_babysitter_unref (sitter); +      return NULL; +    } + +  sitter->have_spawn_errno = FALSE; +  sitter->have_child_status = FALSE; + +  return sitter; +} + +/** + * Increment the reference count on the babysitter object. + * + * @param sitter the babysitter + * @returns the babysitter + */ +DBusBabysitter * +_dbus_babysitter_ref (DBusBabysitter *sitter) +{ +  PING(); +  _dbus_assert (sitter != NULL); +  _dbus_assert (sitter->refcount > 0); + +  sitter->refcount += 1; + +  return sitter; +} + +/** + * Decrement the reference count on the babysitter object. + * + * @param sitter the babysitter + */ +void +_dbus_babysitter_unref (DBusBabysitter *sitter) +{ +  int i; + +  PING(); +  _dbus_assert (sitter != NULL); +  _dbus_assert (sitter->refcount > 0); + +  sitter->refcount -= 1; + +  if (sitter->refcount == 0) +    { +      if (sitter->socket_to_babysitter != -1) +        { +          _dbus_close_socket (sitter->socket_to_babysitter, NULL); +          sitter->socket_to_babysitter = -1; +        } + +      if (sitter->socket_to_main != -1) +        { +          _dbus_close_socket (sitter->socket_to_main, NULL); +          sitter->socket_to_main = -1; +        } + +      PING(); +      if (sitter->argv != NULL) +        { +          for (i = 0; i < sitter->argc; i++) +            if (sitter->argv[i] != NULL) +              { +                dbus_free (sitter->argv[i]); +                sitter->argv[i] = NULL; +              } +          dbus_free (sitter->argv); +          sitter->argv = NULL; +        } + +      if (sitter->envp != NULL) +        { +          char **e = sitter->envp; + +          while (*e) +            dbus_free (*e++); +          dbus_free (sitter->envp); +          sitter->envp = NULL; +        } + +      if (sitter->child_handle != NULL) +        { +          CloseHandle (sitter->child_handle); +          sitter->child_handle = NULL; +        } + +      if (sitter->sitter_watch) +        { +          _dbus_watch_invalidate (sitter->sitter_watch); +          _dbus_watch_unref (sitter->sitter_watch); +          sitter->sitter_watch = NULL; +        } + +      if (sitter->watches) +        _dbus_watch_list_free (sitter->watches); + +      if (sitter->start_sync_event != NULL) +        { +          PING(); +          CloseHandle (sitter->start_sync_event); +          sitter->end_sync_event = NULL; +        } + +#ifdef DBUS_BUILD_TESTS +      if (sitter->end_sync_event != NULL) +        { +          CloseHandle (sitter->end_sync_event); +          sitter->end_sync_event = NULL; +        } +#endif + +      dbus_free (sitter->executable); + +      dbus_free (sitter); +    } +} + +void +_dbus_babysitter_kill_child (DBusBabysitter *sitter) +{ +  PING(); +  if (sitter->child_handle == NULL) +    return; /* child is already dead, or we're so hosed we'll never recover */ + +  PING(); +  TerminateProcess (sitter->child_handle, 12345); +} + +/** + * Checks whether the child has exited, without blocking. + * + * @param sitter the babysitter + */ +dbus_bool_t +_dbus_babysitter_get_child_exited (DBusBabysitter *sitter) +{ +  PING(); +  return (sitter->child_handle == NULL); +} + +/** + * Sets the #DBusError with an explanation of why the spawned + * child process exited (on a signal, or whatever). If + * the child process has not exited, does nothing (error + * will remain unset). + * + * @param sitter the babysitter + * @param error an error to fill in + */ +void +_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, +                                       DBusError      *error) +{ +  PING(); +  if (!_dbus_babysitter_get_child_exited (sitter)) +    return; + +  PING(); +  if (sitter->have_spawn_errno) +    { +      dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, +                      "Failed to execute program %s: %s", +                      sitter->executable, _dbus_strerror (sitter->spawn_errno)); +    } +  else if (sitter->have_child_status) +    { +      PING(); +      dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, +                      "Process %s exited with status %d", +                      sitter->executable, sitter->child_status); +    } +  else +    { +      PING(); +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Process %s exited, status unknown", +                      sitter->executable); +    } +  PING(); +} + +dbus_bool_t +_dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter, +                                      DBusAddWatchFunction       add_function, +                                      DBusRemoveWatchFunction    remove_function, +                                      DBusWatchToggledFunction   toggled_function, +                                      void                      *data, +                                      DBusFreeFunction           free_data_function) +{ +  PING(); +  return _dbus_watch_list_set_functions (sitter->watches, +                                         add_function, +                                         remove_function, +                                         toggled_function, +                                         data, +                                         free_data_function); +} + +static dbus_bool_t +handle_watch (DBusWatch       *watch, +              unsigned int     condition, +              void            *data) +{ +  DBusBabysitter *sitter = data; + +  /* On Unix dbus-spawn uses a babysitter *process*, thus it has to +   * actually send the exit statuses, error codes and whatnot through +   * sockets and/or pipes. On Win32, the babysitter is jus a thread, +   * so it can set the status fields directly in the babysitter struct +   * just fine. The socket pipe is used just so we can watch it with +   * select(), as soon as anything is written to it we know that the +   * babysitter thread has recorded the status in the babysitter +   * struct. +   */ + +  PING(); +  _dbus_close_socket (sitter->socket_to_babysitter, NULL); +  PING(); +  sitter->socket_to_babysitter = -1; + +  return TRUE; +} + +/* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ +static int +protect_argv (char  **argv, +              char ***new_argv) +{ +  int i; +  int argc = 0; + +  while (argv[argc]) +    ++argc; +  *new_argv = dbus_malloc ((argc + 1) * sizeof (char *)); +  if (*new_argv == NULL) +    return -1; + +  for (i = 0; i < argc; i++) +    (*new_argv)[i] = NULL; + +  /* Quote each argv element if necessary, so that it will get +   * reconstructed correctly in the C runtime startup code.  Note that +   * the unquoting algorithm in the C runtime is really weird, and +   * rather different than what Unix shells do. See stdargv.c in the C +   * runtime sources (in the Platform SDK, in src/crt). +   * +   * Note that an new_argv[0] constructed by this function should +   * *not* be passed as the filename argument to a spawn* or exec* +   * family function. That argument should be the real file name +   * without any quoting. +   */ +  for (i = 0; i < argc; i++) +    { +      char *p = argv[i]; +      char *q; +      int len = 0; +      int need_dblquotes = FALSE; +      while (*p) +        { +          if (*p == ' ' || *p == '\t') +            need_dblquotes = TRUE; +          else if (*p == '"') +            len++; +          else if (*p == '\\') +            { +              char *pp = p; +              while (*pp && *pp == '\\') +                pp++; +              if (*pp == '"') +                len++; +            } +          len++; +          p++; +        } + +      q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1); + +      if (q == NULL) +        return -1; + + +      p = argv[i]; + +      if (need_dblquotes) +        *q++ = '"'; + +      while (*p) +        { +          if (*p == '"') +            *q++ = '\\'; +          else if (*p == '\\') +            { +              char *pp = p; +              while (*pp && *pp == '\\') +                pp++; +              if (*pp == '"') +                *q++ = '\\'; +            } +          *q++ = *p; +          p++; +        } + +      if (need_dblquotes) +        *q++ = '"'; +      *q++ = '\0'; +      /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ +    } +  (*new_argv)[argc] = NULL; + +  return argc; +} + +static unsigned __stdcall +babysitter (void *parameter) +{ +  DBusBabysitter *sitter = (DBusBabysitter *) parameter; +  DBusSocket *sock; +  PING(); +  _dbus_babysitter_ref (sitter); + +  if (sitter->child_setup) +    { +      PING(); +      (*sitter->child_setup) (sitter->user_data); +    } + +  _dbus_verbose ("babysitter: spawning %s\n", sitter->executable); +  fprintf (stderr, "babysitter: spawning %s\n", sitter->executable); + +  PING(); +  if (sitter->envp != NULL) +    sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable, +                           (const char * const *) sitter->argv, +                           (const char * const *) sitter->envp); +  else +    sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable, +                                            (const char * const *) sitter->argv); + +  PING(); +  if (sitter->child_handle == (HANDLE) -1) +    { +      sitter->child_handle = NULL; +      sitter->have_spawn_errno = TRUE; +      sitter->spawn_errno = errno; +    } + +  PING(); +  SetEvent (sitter->start_sync_event); + +  if (sitter->child_handle != NULL) +    { +      int ret; +      DWORD status; + +      PING(); +      WaitForSingleObject (sitter->child_handle, INFINITE); + +      PING(); +      ret = GetExitCodeProcess (sitter->child_handle, &status); + +      sitter->child_status = status; +      sitter->have_child_status = TRUE; + +      CloseHandle (sitter->child_handle); +      sitter->child_handle = NULL; +    } + +#ifdef DBUS_BUILD_TESTS +  SetEvent (sitter->end_sync_event); +#endif + +  PING(); +  _dbus_handle_to_socket (sitter->socket_to_main, &sock); +  send (sock->fd, " ", 1, 0); + +  _dbus_babysitter_unref (sitter); + +  return 0; +} + +dbus_bool_t +_dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p, +                                   char                     **argv, +                                   char                     **envp, +                                   DBusSpawnChildSetupFunc    child_setup, +                                   void                      *user_data, +                                   DBusError                 *error) +{ +  DBusBabysitter *sitter; +  HANDLE sitter_thread; +  int sitter_thread_id; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  *sitter_p = NULL; + +  PING(); +  sitter = _dbus_babysitter_new (); +  if (sitter == NULL) +    { +      _DBUS_SET_OOM (error); +      return FALSE; +    } + +  sitter->child_setup = child_setup; +  sitter->user_data = user_data; + +  sitter->executable = _dbus_strdup (argv[0]); +  if (sitter->executable == NULL) +    { +      _DBUS_SET_OOM (error); +      goto out0; +    } + +  PING(); +  if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter, +                               &sitter->socket_to_main, +                               FALSE, error)) +    goto out0; + +  sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, +                                          DBUS_WATCH_READABLE, +                                          TRUE, handle_watch, sitter, NULL); +  PING(); +  if (sitter->sitter_watch == NULL) +    { +      _DBUS_SET_OOM (error); +      goto out0; +    } + +  PING(); +  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch)) +    { +      _DBUS_SET_OOM (error); +      goto out0; +    } + +  sitter->argc = protect_argv (argv, &sitter->argv); +  if (sitter->argc == -1) +    { +      _DBUS_SET_OOM (error); +      goto out0; +    } +  sitter->envp = envp; + +  PING(); +  sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter, +                  sitter, 0, &sitter_thread_id); + +  if (sitter_thread == 0) +    { +      PING(); +      dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, +                            "Failed to create new thread"); +      goto out0; +    } +  CloseHandle (sitter_thread); + +  PING(); +  WaitForSingleObject (sitter->start_sync_event, INFINITE); + +  PING(); +  if (sitter_p != NULL) +    *sitter_p = sitter; +  else +    _dbus_babysitter_unref (sitter); + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  PING(); +  return TRUE; + +out0: +  _dbus_babysitter_unref (sitter); + +  return FALSE; +} + +#ifdef DBUS_BUILD_TESTS + +#define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) + +static void +_dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) +{ +  if (sitter->child_handle == NULL) +    return; + +  WaitForSingleObject (sitter->end_sync_event, INFINITE); +} + +static dbus_bool_t +check_spawn_nonexistent (void *data) +{ +  char *argv[4] = { NULL, NULL, NULL, NULL }; +  DBusBabysitter *sitter; +  DBusError error; + +  sitter = NULL; + +  dbus_error_init (&error); + +  /*** Test launching nonexistent binary */ + +  argv[0] = "/this/does/not/exist/32542sdgafgafdg"; +  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, +                                         NULL, NULL, +                                         &error)) +    { +      _dbus_babysitter_block_for_child_exit (sitter); +      _dbus_babysitter_set_child_exit_error (sitter, &error); +    } + +  if (sitter) +    _dbus_babysitter_unref (sitter); + +  if (!dbus_error_is_set (&error)) +    { +      _dbus_warn ("Did not get an error launching nonexistent executable\n"); +      return FALSE; +    } + +  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || +        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) +    { +      _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", +                  error.name, error.message); +      dbus_error_free (&error); +      return FALSE; +    } + +  dbus_error_free (&error); + +  return TRUE; +} + +static dbus_bool_t +check_spawn_segfault (void *data) +{ +  char *argv[4] = { NULL, NULL, NULL, NULL }; +  DBusBabysitter *sitter; +  DBusError error; + +  sitter = NULL; + +  dbus_error_init (&error); + +  /*** Test launching segfault binary */ + +  argv[0] = TEST_SEGFAULT_BINARY; +  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, +                                         NULL, NULL, +                                         &error)) +    { +      _dbus_babysitter_block_for_child_exit (sitter); +      _dbus_babysitter_set_child_exit_error (sitter, &error); +    } + +  if (sitter) +    _dbus_babysitter_unref (sitter); + +  if (!dbus_error_is_set (&error)) +    { +      _dbus_warn ("Did not get an error launching segfaulting binary\n"); +      return FALSE; +    } + +  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || +        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) +    { +      _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", +                  error.name, error.message); +      dbus_error_free (&error); +      return FALSE; +    } + +  dbus_error_free (&error); + +  return TRUE; +} + +static dbus_bool_t +check_spawn_exit (void *data) +{ +  char *argv[4] = { NULL, NULL, NULL, NULL }; +  DBusBabysitter *sitter; +  DBusError error; + +  sitter = NULL; + +  dbus_error_init (&error); + +  /*** Test launching exit failure binary */ + +  argv[0] = TEST_EXIT_BINARY; +  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, +                                         NULL, NULL, +                                         &error)) +    { +      _dbus_babysitter_block_for_child_exit (sitter); +      _dbus_babysitter_set_child_exit_error (sitter, &error); +    } + +  if (sitter) +    _dbus_babysitter_unref (sitter); + +  if (!dbus_error_is_set (&error)) +    { +      _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); +      return FALSE; +    } + +  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || +        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) +    { +      _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", +                  error.name, error.message); +      dbus_error_free (&error); +      return FALSE; +    } + +  dbus_error_free (&error); + +  return TRUE; +} + +static dbus_bool_t +check_spawn_and_kill (void *data) +{ +  char *argv[4] = { NULL, NULL, NULL, NULL }; +  DBusBabysitter *sitter; +  DBusError error; + +  sitter = NULL; + +  dbus_error_init (&error); + +  /*** Test launching sleeping binary then killing it */ + +  argv[0] = TEST_SLEEP_FOREVER_BINARY; +  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, +                                         NULL, NULL, +                                         &error)) +    { +      _dbus_babysitter_kill_child (sitter); + +      _dbus_babysitter_block_for_child_exit (sitter); + +      _dbus_babysitter_set_child_exit_error (sitter, &error); +    } + +  if (sitter) +    _dbus_babysitter_unref (sitter); + +  if (!dbus_error_is_set (&error)) +    { +      _dbus_warn ("Did not get an error after killing spawned binary\n"); +      return FALSE; +    } + +  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || +        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) +    { +      _dbus_warn ("Not expecting error when killing executable: %s: %s\n", +                  error.name, error.message); +      dbus_error_free (&error); +      return FALSE; +    } + +  dbus_error_free (&error); + +  return TRUE; +} + +dbus_bool_t +_dbus_spawn_test (const char *test_data_dir) +{ +  if (!_dbus_test_oom_handling ("spawn_nonexistent", +                                check_spawn_nonexistent, +                                NULL)) +    return FALSE; + +  /* Don't run the obnoxious segfault test by default, +   * it's a pain to have to click all those error boxes. +   */ +  if (getenv ("DO_SEGFAULT_TEST")) +    if (!_dbus_test_oom_handling ("spawn_segfault", +                                  check_spawn_segfault, +                                  NULL)) +      return FALSE; + +  if (!_dbus_test_oom_handling ("spawn_exit", +                                check_spawn_exit, +                                NULL)) +    return FALSE; + +  if (!_dbus_test_oom_handling ("spawn_and_kill", +                                check_spawn_and_kill, +                                NULL)) +    return FALSE; + +  return TRUE; +} +#endif diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c new file mode 100644 index 00000000..331c9446 --- /dev/null +++ b/dbus/dbus-sysdeps-util-win.c @@ -0,0 +1,821 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus + *  + * Copyright (C) 2002, 2003, 2004, 2005  Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#undef open + +#define STRSAFE_NO_DEPRECATE + +#include "dbus-sysdeps.h" +#include "dbus-internals.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#include "dbus-sysdeps.h" +#include "dbus-sysdeps-win.h" +#include "dbus-memory.h" + +#include <io.h> +#include <sys/stat.h> +#include <aclapi.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> + +/** + * Does the chdir, fork, setsid, etc. to become a daemon process. + * + * @param pidfile #NULL, or pidfile to create + * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_become_daemon (const DBusString *pidfile, +                     int               print_pid_fd, +                     DBusError        *error) +{ +  return TRUE; +} + +/** + * Creates a file containing the process ID. + * + * @param filename the filename to write to + * @param pid our process ID + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_write_pid_file (const DBusString *filename, +                      unsigned long     pid, +                      DBusError        *error) +{ +  const char *cfilename; +  DBusFile file; +  FILE *f; + +  cfilename = _dbus_string_get_const_data (filename); + +  if (!_dbus_open_file(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644)) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to open \"%s\": %s", cfilename, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  if ((f = fdopen (file.FDATA, "w")) == NULL) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno)); +      _dbus_close_file (&file, NULL); +      return FALSE; +    } + +  if (fprintf (f, "%lu\n", pid) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to write to \"%s\": %s", cfilename, +                      _dbus_strerror (errno)); + +      fclose (f); +      return FALSE; +    } + +  if (fclose (f) == EOF) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to close \"%s\": %s", cfilename, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  return TRUE; +} + +/** + * Changes the user and group the bus is running as. + * + * @param uid the new user ID + * @param gid the new group ID + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_change_identity  (dbus_uid_t     uid, +                        dbus_gid_t     gid, +                        DBusError     *error) +{ +  return TRUE; +} + +/** Checks if user is at the console +* +* @param username user to check +* @param error return location for errors +* @returns #TRUE is the user is at the consolei and there are no errors +*/ +dbus_bool_t +_dbus_user_at_console(const char *username, +                      DBusError  *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +#else +  dbus_bool_t retval = FALSE; +  wchar_t *wusername; +  DWORD sid_length; +  PSID user_sid, console_user_sid; +  HWINSTA winsta; + +  wusername = _dbus_win_utf8_to_utf16 (username, error); +  if (!wusername) +    return FALSE; + +  if (!_dbus_win_account_to_sid (wusername, &user_sid, error)) +    goto out0; + +  /* Now we have the SID for username. Get the SID of the +   * user at the "console" (window station WinSta0) +   */ +  if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL))) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out2; +    } + +  sid_length = 0; +  GetUserObjectInformation (winsta, UOI_USER_SID, +                            NULL, 0, &sid_length); +  if (sid_length == 0) +    { +      /* Nobody is logged on */ +      goto out2; +    } + +  if (sid_length < 0 || sid_length > 1000) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length"); +      goto out3; +    } + +  console_user_sid = dbus_malloc (sid_length); +  if (!console_user_sid) +    { +      _DBUS_SET_OOM (error); +      goto out3; +    } + +  if (!GetUserObjectInformation (winsta, UOI_USER_SID, +                                 console_user_sid, sid_length, &sid_length)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out4; +    } + +  if (!IsValidSid (console_user_sid)) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); +      goto out4; +    } + +  retval = EqualSid (user_sid, console_user_sid); + +out4: +  dbus_free (console_user_sid); +out3: +  CloseWindowStation (winsta); +out2: +  dbus_free (user_sid); +out0: +  dbus_free (wusername); + +  return retval; +#endif //DBUS_WINCE +} + +/** + * Removes a directory; Directory must be empty + *  + * @param filename directory filename + * @param error initialized error object + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_delete_directory (const DBusString *filename, +                        DBusError        *error) +{ +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  if (rmdir (filename_c) != 0) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Failed to remove directory %s: %s\n", +                      filename_c, _dbus_strerror (errno)); +      return FALSE; +    } + +  return TRUE; +} + +/** Installs a signal handler + * + * @param sig the signal to handle + * @param handler the handler + */ +void +_dbus_set_signal_handler (int               sig, +                          DBusSignalHandler handler) +{ +  _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n"); +} + +/** + * stat() wrapper. + * + * @param filename the filename to stat + * @param statbuf the stat info to fill in + * @param error return location for error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_stat(const DBusString *filename, +           DBusStat         *statbuf, +           DBusError        *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +	//TODO +#else +  const char *filename_c; +#if !defined(DBUS_WIN) && !defined(DBUS_WINCE) + +  struct stat sb; +#else + +  WIN32_FILE_ATTRIBUTE_DATA wfad; +  char *lastdot; +  DWORD rc; +  PSID owner_sid, group_sid; +  PSECURITY_DESCRIPTOR sd; +#endif + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return FALSE; +    } + +  if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) +    statbuf->mode = _S_IFDIR; +  else +    statbuf->mode = _S_IFREG; + +  statbuf->mode |= _S_IREAD; +  if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY) +    statbuf->mode |= _S_IWRITE; + +  lastdot = strrchr (filename_c, '.'); +  if (lastdot && stricmp (lastdot, ".exe") == 0) +    statbuf->mode |= _S_IEXEC; + +  statbuf->mode |= (statbuf->mode & 0700) >> 3; +  statbuf->mode |= (statbuf->mode & 0700) >> 6; + +  statbuf->nlink = 1; + +  sd = NULL; +  rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT, +                             OWNER_SECURITY_INFORMATION | +                             GROUP_SECURITY_INFORMATION, +                             &owner_sid, &group_sid, +                             NULL, NULL, +                             &sd); +  if (rc != ERROR_SUCCESS) +    { +      _dbus_win_set_error_from_win_error (error, rc); +      if (sd != NULL) +        LocalFree (sd); +      return FALSE; +    } + +  statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid); +  statbuf->gid = _dbus_win_sid_to_uid_t (group_sid); + +  LocalFree (sd); + +  statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow; + +  statbuf->atime = +    (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) + +     wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000); + +  statbuf->mtime = +    (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) + +     wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000); + +  statbuf->ctime = +    (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) + +     wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000); + +  return TRUE; +#endif //DBUS_WINCE +} + + +#ifdef HAVE_DIRENT_H + +// mingw ships with dirent.h +#include <dirent.h> +#define _dbus_opendir opendir +#define _dbus_readdir readdir +#define _dbus_closedir closedir + +#else + +#ifdef HAVE_IO_H +#include <io.h> // win32 file functions +#endif + +#include <sys/types.h> +#include <stdlib.h> + +/* This file is part of the KDE project +Copyright (C) 2000 Werner Almesberger + +libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this program; see the file COPYING.  If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. +*/ +#define HAVE_NO_D_NAMLEN	/* no struct dirent->d_namlen */ +#define HAVE_DD_LOCK  		/* have locking mechanism */ + +#define MAXNAMLEN 255		/* sizeof(struct dirent.d_name)-1 */ + +#define __dirfd(dir) (dir)->dd_fd + +/* struct dirent - same as Unix */ +struct dirent +  { +    long d_ino;                    /* inode (always 1 in WIN32) */ +    off_t d_off;                /* offset to this dirent */ +    unsigned short d_reclen;    /* length of d_name */ +    char d_name[_MAX_FNAME+1];    /* filename (null terminated) */ +  }; + +/* typedef DIR - not the same as Unix */ +typedef struct +  { +    long handle;                /* _findfirst/_findnext handle */ +    short offset;                /* offset into directory */ +    short finished;             /* 1 if there are not more files */ +    struct _finddata_t fileinfo;  /* from _findfirst/_findnext */ +    char *dir;                  /* the dir we are reading */ +    struct dirent dent;         /* the dirent to return */ +  } +DIR; + +/********************************************************************** +* Implement dirent-style opendir/readdir/closedir on Window 95/NT +* +* Functions defined are opendir(), readdir() and closedir() with the +* same prototypes as the normal dirent.h implementation. +* +* Does not implement telldir(), seekdir(), rewinddir() or scandir(). +* The dirent struct is compatible with Unix, except that d_ino is +* always 1 and d_off is made up as we go along. +* +* The DIR typedef is not compatible with Unix. +**********************************************************************/ + +DIR * _dbus_opendir(const char *dir) +{ +  DIR *dp; +  char *filespec; +  long handle; +  int index; + +  filespec = malloc(strlen(dir) + 2 + 1); +  strcpy(filespec, dir); +  index = strlen(filespec) - 1; +  if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\')) +    filespec[index] = '\0'; +  strcat(filespec, "\\*"); + +  dp = (DIR *)malloc(sizeof(DIR)); +  dp->offset = 0; +  dp->finished = 0; +  dp->dir = strdup(dir); + +  if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) +    { +      if (errno == ENOENT) +        dp->finished = 1; +      else +        return NULL; +    } + +  dp->handle = handle; +  free(filespec); + +  return dp; +} + +struct dirent * _dbus_readdir(DIR *dp) +  { +    if (!dp || dp->finished) +      return NULL; + +    if (dp->offset != 0) +      { +        if (_findnext(dp->handle, &(dp->fileinfo)) < 0) +          { +            dp->finished = 1; +            errno = 0; +            return NULL; +          } +      } +    dp->offset++; + +    strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME); +    dp->dent.d_ino = 1; +    dp->dent.d_reclen = strlen(dp->dent.d_name); +    dp->dent.d_off = dp->offset; + +    return &(dp->dent); +  } + + +int _dbus_closedir(DIR *dp) +{ +  if (!dp) +    return 0; +  _findclose(dp->handle); +  if (dp->dir) +    free(dp->dir); +  if (dp) +    free(dp); + +  return 0; +} + +#endif //#ifdef HAVE_DIRENT_H + +/** + * Internals of directory iterator + */ +struct DBusDirIter +  { +    DIR *d; /**< The DIR* from opendir() */ + +  }; + +/** + * Open a directory to iterate over. + * + * @param filename the directory name + * @param error exception return object or #NULL + * @returns new iterator, or #NULL on error + */ +DBusDirIter* +_dbus_directory_open (const DBusString *filename, +                      DBusError        *error) +{ +  DIR *d; +  DBusDirIter *iter; +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  d = _dbus_opendir (filename_c); +  if (d == NULL) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to read directory \"%s\": %s", +                      filename_c, +                      _dbus_strerror (errno)); +      return NULL; +    } +  iter = dbus_new0 (DBusDirIter, 1); +  if (iter == NULL) +    { +      _dbus_closedir (d); +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, +                      "Could not allocate memory for directory iterator"); +      return NULL; +    } + +  iter->d = d; + +  return iter; +} + +/** + * Get next file in the directory. Will not return "." or ".."  on + * UNIX. If an error occurs, the contents of "filename" are + * undefined. The error is never set if the function succeeds. + * + * @todo for thread safety, I think we have to use + * readdir_r(). (GLib has the same issue, should file a bug.) + * + * @param iter the iterator + * @param filename string to be set to the next file in the dir + * @param error return location for error + * @returns #TRUE if filename was filled in with a new filename + */ +dbus_bool_t +_dbus_directory_get_next_file (DBusDirIter      *iter, +                               DBusString       *filename, +                               DBusError        *error) +{ +  struct dirent *ent; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +again: +  errno = 0; +  ent = _dbus_readdir (iter->d); +  if (ent == NULL) +    { +      if (errno != 0) +        dbus_set_error (error, +                        _dbus_error_from_errno (errno), +                        "%s", _dbus_strerror (errno)); +      return FALSE; +    } +  else if (ent->d_name[0] == '.' && +           (ent->d_name[1] == '\0' || +            (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) +    goto again; +  else +    { +      _dbus_string_set_length (filename, 0); +      if (!_dbus_string_append (filename, ent->d_name)) +        { +          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, +                          "No memory to read directory entry"); +          return FALSE; +        } +      else +        return TRUE; +    } +} + +/** + * Closes a directory iteration. + */ +void +_dbus_directory_close (DBusDirIter *iter) +{ +  _dbus_closedir (iter->d); +  dbus_free (iter); +} + +/** + * Checks whether the filename is an absolute path + * + * @param filename the filename + * @returns #TRUE if an absolute path + */ +dbus_bool_t +_dbus_path_is_absolute (const DBusString *filename) +{ +  if (_dbus_string_get_length (filename) > 0) +    return _dbus_string_get_byte (filename, 1) == ':' +           || _dbus_string_get_byte (filename, 0) == '\\' +           || _dbus_string_get_byte (filename, 0) == '/'; +  else +    return FALSE; +} + + +static dbus_bool_t +fill_group_info(DBusGroupInfo    *info, +                dbus_gid_t        gid, +                const DBusString *groupname, +                DBusError        *error) +{ +  const char *group_c_str; + +  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); +  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); + +  if (groupname) +    group_c_str = _dbus_string_get_const_data (groupname); +  else +    group_c_str = NULL; + +  if (group_c_str) +    { +      PSID group_sid; +      wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error); + +      if (!wgroupname) +        return FALSE; + +      if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error)) +        { +          dbus_free (wgroupname); +          return FALSE; +        } + +      info->gid = _dbus_win_sid_to_uid_t (group_sid); +      info->groupname = _dbus_strdup (group_c_str); + +      dbus_free (group_sid); +      dbus_free (wgroupname); + +      return TRUE; +    } +  else +    { +      dbus_bool_t retval = FALSE; +      wchar_t *wname, *wdomain; +      char *name, *domain; + +      info->gid = gid; + +      if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error)) +        return FALSE; + +      name = _dbus_win_utf16_to_utf8 (wname, error); +      if (!name) +        goto out0; + +      domain = _dbus_win_utf16_to_utf8 (wdomain, error); +      if (!domain) +        goto out1; + +      info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1); + +      strcpy (info->groupname, domain); +      strcat (info->groupname, "\\"); +      strcat (info->groupname, name); + +      retval = TRUE; + +      dbus_free (domain); +out1: +      dbus_free (name); +out0: +      dbus_free (wname); +      dbus_free (wdomain); + +      return retval; +    } +} + +/** + * Initializes the given DBusGroupInfo struct + * with information about the given group ID. + * + * @param info the group info struct + * @param gid group ID + * @param error the error return + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_group_info_fill_gid (DBusGroupInfo *info, +                           dbus_gid_t     gid, +                           DBusError     *error) +{ +  return fill_group_info (info, gid, NULL, error); +} + +/** + * Initializes the given DBusGroupInfo struct + * with information about the given group name. + * + * @param info the group info struct + * @param groupname name of group + * @param error the error return + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_group_info_fill (DBusGroupInfo    *info, +                       const DBusString *groupname, +                       DBusError        *error) +{ +  return fill_group_info (info, DBUS_GID_UNSET, +                          groupname, error); +} + +/** @} */ /* End of DBusInternalsUtils functions */ + +/** + * @addtogroup DBusString + * + * @{ + */ +/** + * Get the directory name from a complete filename + * @param filename the filename + * @param dirname string to append directory name to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_get_dirname(const DBusString *filename, +                         DBusString       *dirname) +{ +  int sep; + +  _dbus_assert (filename != dirname); +  _dbus_assert (filename != NULL); +  _dbus_assert (dirname != NULL); + +  /* Ignore any separators on the end */ +  sep = _dbus_string_get_length (filename); +  if (sep == 0) +    return _dbus_string_append (dirname, "."); /* empty string passed in */ + +  while (sep > 0 && +         (_dbus_string_get_byte (filename, sep - 1) == '/' || +          _dbus_string_get_byte (filename, sep - 1) == '\\')) +    --sep; + +  _dbus_assert (sep >= 0); + +  if (sep == 0 || +      (sep == 2 && +       _dbus_string_get_byte (filename, 1) == ':' && +       isalpha (_dbus_string_get_byte (filename, 0)))) +    return _dbus_string_copy_len (filename, 0, sep + 1, +                                  dirname, _dbus_string_get_length (dirname)); + +  { +    int sep1, sep2; +    _dbus_string_find_byte_backward (filename, sep, '/', &sep1); +    _dbus_string_find_byte_backward (filename, sep, '\\', &sep2); + +    sep = MAX (sep1, sep2); +  } +  if (sep < 0) +    return _dbus_string_append (dirname, "."); + +  while (sep > 0 && +         (_dbus_string_get_byte (filename, sep - 1) == '/' || +          _dbus_string_get_byte (filename, sep - 1) == '\\')) +    --sep; + +  _dbus_assert (sep >= 0); + +  if ((sep == 0 || +       (sep == 2 && +        _dbus_string_get_byte (filename, 1) == ':' && +        isalpha (_dbus_string_get_byte (filename, 0)))) +      && +      (_dbus_string_get_byte (filename, sep) == '/' || +       _dbus_string_get_byte (filename, sep) == '\\')) +    return _dbus_string_copy_len (filename, 0, sep + 1, +                                  dirname, _dbus_string_get_length (dirname)); +  else +    return _dbus_string_copy_len (filename, 0, sep - 0, +                                  dirname, _dbus_string_get_length (dirname)); +} + +/** @} */ /* DBusString stuff */ + diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c new file mode 100644 index 00000000..20c2400c --- /dev/null +++ b/dbus/dbus-sysdeps-win.c @@ -0,0 +1,5178 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation) + *  + * Copyright (C) 2002, 2003  Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2005 Novell, Inc. + * Copyright (C) 2006 Ralf Habacker <ralf.habacker@freenet.de> + * Copyright (C) 2006 Peter Kümmel  <syntheticpp@gmx.net> + * Copyright (C) 2006 Christian Ehrlicher <ch.ehrlicher@gmx.de> + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ +#undef open + +#define STRSAFE_NO_DEPRECATE + +#ifndef DBUS_WINCE +#define _WIN32_WINNT 0x0500 +#endif + +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-threads.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#include "dbus-sysdeps-win.h" +#include "dbus-protocol.h" +#include "dbus-hash.h" +#include "dbus-sockets-win.h" +#include "dbus-userdb.h" +#include "dbus-list.h" + +#include <windows.h> +#include <fcntl.h> + +#include <process.h> +#include <sys/stat.h> +#include <sys/types.h> + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + +_DBUS_DEFINE_GLOBAL_LOCK (win_fds); +_DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache); + + +static +void  +_dbus_lock_sockets() +{ +	_dbus_assert (win_fds!=0);  +	_DBUS_LOCK   (win_fds); +} + +static +void  +_dbus_unlock_sockets() +{ +	_dbus_assert (win_fds!=0);  +	_DBUS_UNLOCK (win_fds); +} + +#ifdef _DBUS_WIN_USE_RANDOMIZER +static int  win_encap_randomizer; +#endif +static DBusHashTable *sid_atom_cache = NULL; + + +static DBusString dbusdir; +static int working_dir_init = 0; + +int _dbus_init_working_dir(char *s) +{ +  /* change working directory to one level above  +     of dbus-daemon executable path.   +     This allows the usage of relative path in  +     config files or command line parameters */ +  DBusString daemon_path,bin_path; + +  if (!_dbus_string_init (&daemon_path)) +    return FALSE; +   +  if (!_dbus_string_init (&bin_path)) +    return FALSE; + +  if (!_dbus_string_init (&dbusdir)) +    return FALSE; +   +  _dbus_string_append(&daemon_path,s); +  _dbus_string_get_dirname(&daemon_path,&bin_path); +  _dbus_string_get_dirname(&bin_path,&dbusdir); +  chdir(_dbus_string_get_const_data(&dbusdir)); +  _dbus_verbose ("Change working path to %s\n",_dbus_string_get_const_data (&dbusdir)); +  working_dir_init = 1; +  return TRUE; +} + +DBusString *_dbus_get_working_dir(void) +{ +  if (!working_dir_init)  +    return NULL; +	 +  _dbus_verbose ("retrieving working path %s\n",_dbus_string_get_const_data (&dbusdir)); +  return &dbusdir; +} + +/** + * File interface + * + */ +dbus_bool_t +_dbus_open_file (DBusFile   *file, +                 const char *filename, +                 int         oflag, +                 int         pmode) +{ +  if (pmode!=-1) +    file->FDATA = _open (filename, oflag, pmode); +  else +    file->FDATA = _open (filename, oflag); +  if (file->FDATA >= 0) +    return TRUE; +  else +    { +      file->FDATA = -1; +      return FALSE; +    } +} + +dbus_bool_t +_dbus_close_file (DBusFile  *file, +                  DBusError *error) +{ +  const int fd = file->FDATA; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_assert (fd >= 0); + +  if (_close (fd) == -1) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Could not close fd %d: %s", fd, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  file->FDATA = -1; +  _dbus_verbose ("closed C file descriptor %d:\n",fd); + +  return TRUE; +} + +int +_dbus_read_file(DBusFile   *file, +                DBusString *buffer, +                int         count) +{ +  const int fd = file->FDATA; +  int bytes_read; +  int start; +  char *data; +  _dbus_assert (count >= 0); + +  start = _dbus_string_get_length (buffer); + +  if (!_dbus_string_lengthen (buffer, count)) +    { +      errno = ENOMEM; +      return -1; +    } + +  data = _dbus_string_get_data_len (buffer, start, count); + +  _dbus_assert (fd >= 0); + +  _dbus_verbose ("read: count=%d fd=%d\n", count, fd); +  bytes_read = read (fd, data, count); + +  if (bytes_read == -1) +    _dbus_verbose ("read: failed: %s\n", _dbus_strerror (errno)); +  else +    _dbus_verbose ("read: = %d\n", bytes_read); + +  if (bytes_read < 0) +    { +      /* put length back (note that this doesn't actually realloc anything) */ +      _dbus_string_set_length (buffer, start); +      return -1; +    } +  else +    { +      /* put length back (doesn't actually realloc) */ +      _dbus_string_set_length (buffer, start + bytes_read); + +#if 0 + +      if (bytes_read > 0) +        _dbus_verbose_bytes_of_string (buffer, start, bytes_read); +#endif + +      return bytes_read; +    } +} + +int +_dbus_write_file (DBusFile         *file, +                  const DBusString *buffer, +                  int               start, +                  int               len) +{ +  const int fd = file->FDATA; +  const char *data; +  int bytes_written; + +  data = _dbus_string_get_const_data_len (buffer, start, len); + +  _dbus_assert (fd >= 0); + +  _dbus_verbose ("write: len=%d fd=%d\n", len, fd); +  bytes_written = write (fd, data, len); + +  if (bytes_written == -1) +    _dbus_verbose ("write: failed: %s\n", _dbus_strerror (errno)); +  else +    _dbus_verbose ("write: = %d\n", bytes_written); + +#if 0 + +  if (bytes_written > 0) +    _dbus_verbose_bytes_of_string (buffer, start, bytes_written); +#endif + +  return bytes_written; +} + +dbus_bool_t +_dbus_is_valid_file (DBusFile* file) +{ +  return file->FDATA >= 0; +} + +dbus_bool_t _dbus_fstat (DBusFile    *file, +                         struct stat *sb) +{ +  return fstat(file->FDATA, sb) >= 0; +} + +int +_dbus_write_pipe (DBusPipe          pipe, +                  const DBusString *buffer, +                  int               start, +                  int               len) +{ +	DBusFile file; +	file.FDATA = pipe; +	return _dbus_write_file(&file, buffer, start, len); +} + +int +_dbus_read_pipe(DBusPipe    pipe, +                DBusString *buffer, +                int         count) +{ +	DBusFile file; +	file.FDATA = pipe; +	return _dbus_read_file(&file, buffer, count); +} + +#undef FDATA + +/** + * Socket interface + * + */ + +static DBusSocket *win_fds = NULL; +static int win_n_fds = 0; // is this the size? rename to win_fds_size? # + +#if 0 +#define TO_HANDLE(n)   ((n)^win32_encap_randomizer) +#define FROM_HANDLE(n) ((n)^win32_encap_randomizer) +#else +#define TO_HANDLE(n)   ((n)+0x10000000) +#define FROM_HANDLE(n) ((n)-0x10000000) +#define IS_HANDLE(n)   ((n)&0x10000000) +#endif + + +static +void +_dbus_win_deallocate_fd (int fd) +{ +  _DBUS_LOCK (win_fds); +  win_fds[FROM_HANDLE (fd)].is_used = 0; +  _DBUS_UNLOCK (win_fds); +} + +static +int +_dbus_win_allocate_fd (void) +{ +  int i; + +  _DBUS_LOCK (win_fds); + +  if (win_fds == NULL) +    { +#ifdef _DBUS_WIN_USE_RANDOMIZER +      DBusString random; +#endif + +      win_n_fds = 16; +      /* Use malloc to avoid memory leak failure in dbus-test */ +      win_fds = malloc (win_n_fds * sizeof (*win_fds)); + +      _dbus_assert (win_fds != NULL); + +      for (i = 0; i < win_n_fds; i++) +        win_fds[i].is_used = 0; + +#ifdef _DBUS_WIN_USE_RANDOMIZER + +      _dbus_string_init (&random); +      _dbus_generate_random_bytes (&random, sizeof (int)); +      memmove (&win_encap_randomizer, _dbus_string_get_const_data (&random), sizeof (int)); +      win_encap_randomizer &= 0xFF; +      _dbus_string_free (&random); +#endif + +    } + +  for (i = 0; i < win_n_fds && win_fds[i].is_used != 0; i++) +    ; + +  if (i == win_n_fds) +    { +      int oldn = win_n_fds; +      int j; + +      win_n_fds += 16; +      win_fds = realloc (win_fds, win_n_fds * sizeof (*win_fds)); + +      _dbus_assert (win_fds != NULL); + +      for (j = oldn; j < win_n_fds; j++) +        win_fds[i].is_used = 0; +    } + +  memset(&win_fds[i], 0, sizeof(win_fds[i])); + +  win_fds[i].is_used = 1; +  win_fds[i].fd = -1; +  win_fds[i].port_file_fd = -1; +  win_fds[i].close_on_exec = FALSE; +  win_fds[i].non_blocking = FALSE; + +  _DBUS_UNLOCK (win_fds); + +  return i; +} + +static +int +_dbus_create_handle_from_socket (int s) +{ +  int i; +  int handle = -1; + +  // check: parameter must be a valid value +  _dbus_assert(s != -1); +  _dbus_assert(!IS_HANDLE(s)); + +  // get index of a new position in the map +  i = _dbus_win_allocate_fd (); + +  // fill new posiiton in the map: value->index +  win_fds[i].fd = s; +  win_fds[i].is_used = 1; + +  // create handle from the index: index->handle +  handle = TO_HANDLE (i); + +  _dbus_verbose ("_dbus_create_handle_from_value, value: %d, handle: %d\n", s, handle); + +  return handle; +} + +int +_dbus_socket_to_handle (DBusSocket *s) +{ +  int i; +  int handle = -1; + +  // check: parameter must be a valid socket +  _dbus_assert(s != NULL); +  _dbus_assert(s->fd != -1); +  _dbus_assert(!IS_HANDLE(s->fd)); + +  _DBUS_LOCK (win_fds); + +  // at the first call there is no win_fds +  // will be constructed  _dbus_create_handle_from_socket +  // because handle = -1 +  if (win_fds != NULL) +    { +      // search for the value in the map +      // find the index of the value: value->index +      for (i = 0; i < win_n_fds; i++) +        if (win_fds[i].is_used == 1 && win_fds[i].fd == s->fd) +          { +            // create handle from the index: index->handle +            handle = TO_HANDLE (i); +            break; +          } +    } +  _DBUS_UNLOCK (win_fds); + + +  if (handle == -1) +    { +      handle = _dbus_create_handle_from_socket(s->fd); +    } + +  _dbus_assert(handle != -1); + +  return handle; +} + +static +void  +_dbus_handle_to_socket_unlocked (int          handle, +                                 DBusSocket **ptr) +{ +  int i; + +  // check: parameter must be a valid handle +  _dbus_assert(handle != -1); +  _dbus_assert(IS_HANDLE(handle)); +  _dbus_assert(ptr != NULL); + +  // map from handle to index: handle->index +  i = FROM_HANDLE (handle); + +  _dbus_assert (win_fds != NULL); +  _dbus_assert (i >= 0 && i < win_n_fds); + +  // check for if fd is valid +  _dbus_assert (win_fds[i].is_used == 1); + +  // get socket from index: index->socket +  *ptr = &win_fds[i]; + +  _dbus_verbose ("_dbus_socket_to_handle_unlocked: socket=%d, handle=%d, index=%d\n", (*ptr)->fd, handle, i); +} + +void  +_dbus_handle_to_socket (int          handle, +                        DBusSocket **ptr) +{ +  _dbus_lock_sockets(); +  _dbus_handle_to_socket_unlocked (handle, ptr); +  _dbus_unlock_sockets(); +} + +#undef TO_HANDLE +#undef IS_HANDLE +#undef FROM_HANDLE +#define FROM_HANDLE(n) 1==DBUS_WIN_DONT_USE__FROM_HANDLE__DIRECTLY +#define win_fds 1==DBUS_WIN_DONT_USE_win_fds_DIRECTLY + + + + +/** + * Thin wrapper around the read() system call that appends + * the data it reads to the DBusString buffer. It appends + * up to the given count, and returns the same value + * and same errno as read(). The only exception is that + * _dbus_read() handles EINTR for you. _dbus_read() can + * return ENOMEM, even though regular UNIX read doesn't. + * + * @param fd the file descriptor to read from + * @param buffer the buffer to append data to + * @param count the amount of data to read + * @returns the number of bytes read or -1 + */ +int +_dbus_read_socket (int               handle, +                   DBusString       *buffer, +                   int               count) +{ +  DBusSocket *s; +  int bytes_read; +  int start; +  char *data; + +  _dbus_assert (count >= 0); + +  start = _dbus_string_get_length (buffer); + +  if (!_dbus_string_lengthen (buffer, count)) +    { +      errno = ENOMEM; +      return -1; +    } + +  data = _dbus_string_get_data_len (buffer, start, count); + +  _dbus_handle_to_socket(handle, &s); + +  if(s->is_used) +    { +      _dbus_verbose ("recv: count=%d socket=%d\n", count, s->fd); +      bytes_read = recv (s->fd, data, count, 0); +      if (bytes_read == SOCKET_ERROR) +        { +          DBUS_SOCKET_SET_ERRNO(); +          _dbus_verbose ("recv: failed: %s\n", _dbus_strerror (errno)); +          bytes_read = -1; +        } +      else +        _dbus_verbose ("recv: = %d\n", bytes_read); +    } +  else +    { +      _dbus_assert_not_reached ("no valid socket"); +    } + +  if (bytes_read < 0) +    { +      /* put length back (note that this doesn't actually realloc anything) */ +      _dbus_string_set_length (buffer, start); +      return -1; +    } +  else +    { +      /* put length back (doesn't actually realloc) */ +      _dbus_string_set_length (buffer, start + bytes_read); + +#if 0 + +      if (bytes_read > 0) +        _dbus_verbose_bytes_of_string (buffer, start, bytes_read); +#endif + +      return bytes_read; +    } +} + +/** + * Thin wrapper around the write() system call that writes a part of a + * DBusString and handles EINTR for you. + *  + * @param fd the file descriptor to write + * @param buffer the buffer to write data from + * @param start the first byte in the buffer to write + * @param len the number of bytes to try to write + * @returns the number of bytes written or -1 on error + */ +int +_dbus_write_socket (int               handle, +                    const DBusString *buffer, +                    int               start, +                    int               len) +{ +  DBusSocket *s; +  int is_used; +  const char *data; +  int bytes_written; + +  data = _dbus_string_get_const_data_len (buffer, start, len); + +  _dbus_handle_to_socket(handle, &s); + +  if (s->is_used) +    { +      _dbus_verbose ("send: len=%d socket=%d\n", len, s->fd); +      bytes_written = send (s->fd, data, len, 0); +      if (bytes_written == SOCKET_ERROR) +        { +          DBUS_SOCKET_SET_ERRNO(); +          _dbus_verbose ("send: failed: %s\n", _dbus_strerror (errno)); +          bytes_written = -1; +        } +      else +        _dbus_verbose ("send: = %d\n", bytes_written); +    } +  else +    { +      _dbus_assert_not_reached ("unhandled fd type"); +    } + +#if 0 +  if (bytes_written > 0) +    _dbus_verbose_bytes_of_string (buffer, start, bytes_written); +#endif + +  return bytes_written; +} + + +/** + * Closes a file descriptor. + * + * @param fd the file descriptor + * @param error error object + * @returns #FALSE if error set + */ +dbus_bool_t +_dbus_close_socket (int        handle, +                    DBusError *error) +{ +  DBusSocket *s; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_lock_sockets(); + +  _dbus_handle_to_socket_unlocked (handle, &s); + + +  if (s->is_used) +    { +      if (s->port_file_fd >= 0) +        { +          _chsize (s->port_file_fd, 0); +          close (s->port_file_fd); +          s->port_file_fd = -1; +          unlink (_dbus_string_get_const_data (&s->port_file)); +          free ((char *) _dbus_string_get_const_data (&s->port_file)); +        } + +      if (closesocket (s->fd) == SOCKET_ERROR) +        { +          DBUS_SOCKET_SET_ERRNO (); +          dbus_set_error (error, _dbus_error_from_errno (errno), +              "Could not close socket: socket=%d, handle=%d, %s", +                          s->fd, handle, _dbus_strerror (errno)); +          _dbus_unlock_sockets(); +          return FALSE; +        } +      _dbus_verbose ("_dbus_close_socket: socket=%d, handle=%d\n", +                     s->fd, handle); +    } +  else +    { +      _dbus_assert_not_reached ("unhandled fd type"); +    } + +  _dbus_unlock_sockets(); + +  _dbus_win_deallocate_fd (handle); + +  return TRUE; + +} + +/** + * Sets the file descriptor to be close + * on exec. Should be called for all file + * descriptors in D-Bus code. + * + * @param fd the file descriptor + */ +void +_dbus_fd_set_close_on_exec (int handle) +{ +  DBusSocket *s; +  if (handle < 0) +    return; + +  _dbus_lock_sockets(); + +  _dbus_handle_to_socket_unlocked (handle, &s); +  s->close_on_exec = TRUE; + +  _dbus_unlock_sockets(); +} + +/** + * Sets a file descriptor to be nonblocking. + * + * @param fd the file descriptor. + * @param error address of error location. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_set_fd_nonblocking (int             handle, +                          DBusError      *error) +{ +  DBusSocket *s; +  u_long one = 1; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_lock_sockets(); + +  _dbus_handle_to_socket_unlocked(handle, &s); + +  if (s->is_used) +    { +      if (ioctlsocket (s->fd, FIONBIO, &one) == SOCKET_ERROR) +        { +          dbus_set_error (error, _dbus_error_from_errno (WSAGetLastError ()), +                          "Failed to set socket %d:%d to nonblocking: %s", s->fd, +                          _dbus_strerror (WSAGetLastError ())); +          _dbus_unlock_sockets(); +          return FALSE; +        } +    } +  else +    { +      _dbus_assert_not_reached ("unhandled fd type"); +    } + +  _dbus_unlock_sockets(); + +  return TRUE; +} + + +/** + * Like _dbus_write() but will use writev() if possible + * to write both buffers in sequence. The return value + * is the number of bytes written in the first buffer, + * plus the number written in the second. If the first + * buffer is written successfully and an error occurs + * writing the second, the number of bytes in the first + * is returned (i.e. the error is ignored), on systems that + * don't have writev. Handles EINTR for you. + * The second buffer may be #NULL. + * + * @param fd the file descriptor + * @param buffer1 first buffer + * @param start1 first byte to write in first buffer + * @param len1 number of bytes to write from first buffer + * @param buffer2 second buffer, or #NULL + * @param start2 first byte to write in second buffer + * @param len2 number of bytes to write in second buffer + * @returns total bytes written from both buffers, or -1 on error + */ +int +_dbus_write_socket_two (int               handle, +                        const DBusString *buffer1, +                        int               start1, +                        int               len1, +                        const DBusString *buffer2, +                        int               start2, +                        int               len2) +{ +  DBusSocket *s; +  WSABUF vectors[2]; +  const char *data1; +  const char *data2; +  int rc; +  DWORD bytes_written; +  int ret1; + +  _dbus_assert (buffer1 != NULL); +  _dbus_assert (start1 >= 0); +  _dbus_assert (start2 >= 0); +  _dbus_assert (len1 >= 0); +  _dbus_assert (len2 >= 0); + +  _dbus_handle_to_socket(handle, &s); + +  data1 = _dbus_string_get_const_data_len (buffer1, start1, len1); + +  if (buffer2 != NULL) +    data2 = _dbus_string_get_const_data_len (buffer2, start2, len2); +  else +    { +      data2 = NULL; +      start2 = 0; +      len2 = 0; +    } + +  if (s->is_used) +    { +      vectors[0].buf = (char*) data1; +      vectors[0].len = len1; +      vectors[1].buf = (char*) data2; +      vectors[1].len = len2; + +      _dbus_verbose ("WSASend: len1+2=%d+%d socket=%d\n", len1, len2, s->fd); +      rc = WSASend (s->fd, vectors, data2 ? 2 : 1, &bytes_written, +                    0, NULL, NULL); +      if (rc < 0) +        { +          DBUS_SOCKET_SET_ERRNO (); +          _dbus_verbose ("WSASend: failed: %s\n", _dbus_strerror (errno)); +          bytes_written = -1; +        } +      else +        _dbus_verbose ("WSASend: = %ld\n", bytes_written); +      return bytes_written; +    } +  else +    { +      _dbus_assert_not_reached ("unhandled fd type"); +    } +  return 0; +} + +/** + * @def _DBUS_MAX_SUN_PATH_LENGTH + * + * Maximum length of the path to a UNIX domain socket, + * sockaddr_un::sun_path member. POSIX requires that all systems + * support at least 100 bytes here, including the nul termination. + * We use 99 for the max value to allow for the nul. + * + * We could probably also do sizeof (addr.sun_path) + * but this way we are the same on all platforms + * which is probably a good idea. + */ + +/** + * Creates a socket and connects it to the UNIX domain socket at the + * given path.  The connection fd is returned, and is set up as + * nonblocking. + *  + * On Windows there are no UNIX domain sockets. Instead, connects to a + * localhost-bound TCP socket, whose port number is stored in a file + * at the given path. + *  + * Uses abstract sockets instead of filesystem-linked sockets if + * requested (it's possible only on Linux; see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. + * + * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_unix_socket (const char     *path, +                           dbus_bool_t     abstract, +                           DBusError      *error) +{ +#ifdef DBUS_WINCE +	return -1; +#else +  int fd, n, port; +  char buf[7]; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_verbose ("connecting to pseudo-unix socket at %s\n", +                 path); + +  if (abstract) +    { +      dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, +                      "Implementation does not support abstract socket namespace\n"); +      return -1; +    } + +  fd = _sopen (path, O_RDONLY, SH_DENYNO); + +  if (fd == -1) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to open file %s: %s", +                      path, _dbus_strerror (errno)); +      return -1; +    } + +  n = read (fd, buf, sizeof (buf) - 1); +  close (fd); + +  if (n == 0) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Failed to read port number from file %s", +                      path); +      return -1; +    } + +  buf[n] = '\0'; +  port = atoi (buf); + +  if (port <= 0 || port > 0xFFFF) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Invalid port numer in file %s", +                      path); +      return -1; +    } + +  return _dbus_connect_tcp_socket (NULL, port, error); +#endif //DBUS_WINCE + +} + +/** + * Creates a socket and binds it to the given path, + * then listens on the socket. The socket is + * set to be nonblocking. + * + * Uses abstract sockets instead of filesystem-linked + * sockets if requested (it's possible only on Linux; + * see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. + * + * @param path the socket name + * @param abstract #TRUE to use abstract namespace + * @param error return location for errors + * @returns the listening file descriptor or -1 on error + */ +int +_dbus_listen_unix_socket (const char     *path, +                          dbus_bool_t     abstract, +                          DBusError      *error) +{ +#ifdef DBUS_WINCE +	return -1; +#else +  DBusSocket *s; +  int listen_handle; +  struct sockaddr sa; +  int addr_len; +  int filefd; +  int n, l; +  DBusString portstr; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_verbose ("listening on pseudo-unix socket at %s\n", +                 path); + +  if (abstract) +    { +      dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, +                      "Implementation does not support abstract socket namespace\n"); +      return -1; +    } + +  listen_handle = _dbus_listen_tcp_socket (NULL, 0, error); + +  if (listen_handle == -1) +    return -1; + +  _dbus_handle_to_socket(listen_handle, &s); + +  addr_len = sizeof (sa); +  if (getsockname (s->fd, &sa, &addr_len) == SOCKET_ERROR) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "getsockname failed: %s", +                      _dbus_strerror (errno)); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } + +  _dbus_assert (((struct sockaddr_in*) &sa)->sin_family == AF_INET); + +  filefd = _sopen (path, O_CREAT|O_WRONLY|_O_SHORT_LIVED, SH_DENYWR, 0666); + +  if (filefd == -1) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to create pseudo-unix socket port number file %s: %s", +                      path, _dbus_strerror (errno)); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } + +  _dbus_lock_sockets(); +  _dbus_handle_to_socket_unlocked(listen_handle, &s); +  s->port_file_fd = filefd; +  _dbus_unlock_sockets(); + +  /* Use strdup() to avoid memory leak in dbus-test */ +  path = strdup (path); +  if (!path) +    { +      _DBUS_SET_OOM (error); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } + +  _dbus_string_init_const (&s->port_file, path); + +  if (!_dbus_string_init (&portstr)) +    { +      _DBUS_SET_OOM (error); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } + +  if (!_dbus_string_append_int (&portstr, ntohs (((struct sockaddr_in*) &sa)->sin_port))) +    { +      _DBUS_SET_OOM (error); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } + +  l = _dbus_string_get_length (&portstr); +  n = write (filefd, _dbus_string_get_const_data (&portstr), l); +  _dbus_string_free (&portstr); + +  if (n == -1) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to write port number to file %s: %s", +                      path, _dbus_strerror (errno)); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } +  else if (n < l) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to write port number to file %s", +                      path); +      _dbus_close_socket (listen_handle, NULL); +      return -1; +    } + +  return listen_handle; +#endif //DBUS_WINCE +} + +#if 0 + +/** + * Opens the client side of a Windows named pipe. The connection D-BUS + * file descriptor index is returned. It is set up as nonblocking. + *  + * @param path the path to named pipe socket + * @param error return location for error code + * @returns connection D-BUS file descriptor or -1 on error + */ +int +_dbus_connect_named_pipe (const char     *path, +                          DBusError      *error) +{ +  _dbus_assert_not_reached ("not implemented"); +} + +#endif + + +dbus_bool_t +_dbus_account_to_win_sid (const wchar_t  *waccount, +                          void          **ppsid, +                          DBusError      *error) +{ +  dbus_bool_t retval = FALSE; +  DWORD sid_length, wdomain_length; +  SID_NAME_USE use; +  wchar_t *wdomain; + +  *ppsid = NULL; + +  sid_length = 0; +  wdomain_length = 0; +  if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length, +                           NULL, &wdomain_length, &use) +      && GetLastError () != ERROR_INSUFFICIENT_BUFFER) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return FALSE; +    } + +  *ppsid = dbus_malloc (sid_length); +  if (!*ppsid) +    { +      _DBUS_SET_OOM (error); +      return FALSE; +    } + +  wdomain = dbus_new (wchar_t, wdomain_length); +  if (!wdomain) +    { +      _DBUS_SET_OOM (error); +      goto out1; +    } + +  if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length, +                           wdomain, &wdomain_length, &use)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out2; +    } + +  if (!IsValidSid ((PSID) *ppsid)) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); +      goto out2; +    } + +  retval = TRUE; + +out2: +  dbus_free (wdomain); +out1: +  if (!retval) +    { +      dbus_free (*ppsid); +      *ppsid = NULL; +    } + +  return retval; +} + + +dbus_bool_t +fill_win_user_info_name_and_groups (wchar_t 	  *wname, +                                    wchar_t 	  *wdomain, +                                    DBusUserInfo *info, +                                    DBusError    *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +#else +  dbus_bool_t retval = FALSE; +  char *name, *domain; +  LPLOCALGROUP_USERS_INFO_0 local_groups = NULL; +  LPGROUP_USERS_INFO_0 global_groups = NULL; +  DWORD nread, ntotal; + +  name = _dbus_win_utf16_to_utf8 (wname, error); +  if (!name) +    return FALSE; + +  domain = _dbus_win_utf16_to_utf8 (wdomain, error); +  if (!domain) +    goto out0; + +  info->username = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1); +  if (!info->username) +    { +      _DBUS_SET_OOM (error); +      goto out1; +    } + +  strcpy (info->username, domain); +  strcat (info->username, "\\"); +  strcat (info->username, name); + +  info->n_group_ids = 0; +  if (NetUserGetLocalGroups (NULL, wname, 0, LG_INCLUDE_INDIRECT, +                             (LPBYTE *) &local_groups, MAX_PREFERRED_LENGTH, +                             &nread, &ntotal) == NERR_Success) +    { +      DWORD i; +      int n; + +      info->group_ids = dbus_new (dbus_gid_t, nread); +      if (!info->group_ids) +        { +          _DBUS_SET_OOM (error); +          goto out3; +        } + +      for (i = n = 0; i < nread; i++) +        { +          PSID group_sid; +          if (_dbus_account_to_win_sid (local_groups[i].lgrui0_name, +                                        &group_sid, error)) +            { +              info->group_ids[n++] = _dbus_win_sid_to_uid_t (group_sid); +              dbus_free (group_sid); +            } +        } +      info->n_group_ids = n; +    } + +  if (NetUserGetGroups (NULL, wname, 0, +                        (LPBYTE *) &global_groups, MAX_PREFERRED_LENGTH, +                        &nread, &ntotal) == NERR_Success) +    { +      DWORD i; +      int n = info->n_group_ids; + +      info->group_ids = dbus_realloc (info->group_ids, (n + nread) * sizeof (dbus_gid_t)); +      if (!info->group_ids) +        { +          _DBUS_SET_OOM (error); +          goto out4; +        } + +      for (i = 0; i < nread; i++) +        { +          PSID group_sid; +          if (_dbus_account_to_win_sid (global_groups[i].grui0_name, +                                        &group_sid, error)) +            { +              info->group_ids[n++] = _dbus_win_sid_to_uid_t (group_sid); +              dbus_free (group_sid); +            } +        } +      info->n_group_ids = n; +    } + +  if (info->n_group_ids > 0) +    { +      /* FIXME: find out actual primary group */ +      info->primary_gid = info->group_ids[0]; +    } +  else +    { +      info->group_ids = dbus_new (dbus_gid_t, 1); +      info->n_group_ids = 1; +      info->group_ids[0] = DBUS_GID_UNSET; +      info->primary_gid = DBUS_GID_UNSET; +    } + +  retval = TRUE; + +out4: +  if (global_groups != NULL) +    NetApiBufferFree (global_groups); +out3: +  if (local_groups != NULL) +    NetApiBufferFree (local_groups); +out1: +  dbus_free (domain); +out0: +  dbus_free (name); + +  return retval; +#endif //DBUS_WINCE +} + +dbus_bool_t +fill_win_user_info_homedir (wchar_t  	 *wname, +                            wchar_t  	 *wdomain, +                            DBusUserInfo *info, +                            DBusError    *error) +{ +#ifdef DBUS_WINCE +	//TODO +	return TRUE; +#else +  dbus_bool_t retval = FALSE; +  USER_INFO_1 *user_info = NULL; +  wchar_t wcomputername[MAX_COMPUTERNAME_LENGTH + 1]; +  DWORD wcomputername_length = MAX_COMPUTERNAME_LENGTH + 1; +  dbus_bool_t local_computer; +  wchar_t *dc = NULL; +  NET_API_STATUS ret = 0; + +  /* If the domain is this computer's name, assume it's a local user. +   * Otherwise look up a DC for the domain, and ask it. +   */ + +  GetComputerNameW (wcomputername, &wcomputername_length); +  local_computer = (wcsicmp (wcomputername, wdomain) == 0); + +  if (!local_computer) +    { +      ret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &dc); +      if (ret != NERR_Success) +        { +          info->homedir = _dbus_strdup ("\\"); +          _dbus_warn("NetGetAnyDCName() failed with errorcode %d '%s'\n",ret,_dbus_lm_strerror(ret)); +          return TRUE; +        } +    } + +  /* No way to find out the profile of another user, let's try the +   * "home directory" from NetUserGetInfo's USER_INFO_1. +   */ +  ret = NetUserGetInfo (dc, wname, 1, (LPBYTE *) &user_info); +  if (ret == NERR_Success ) +    if(user_info->usri1_home_dir != NULL && +        user_info->usri1_home_dir != (LPWSTR)0xfeeefeee &&  /* freed memory http://www.gamedev.net/community/forums/topic.asp?topic_id=158402 */ +        user_info->usri1_home_dir[0] != '\0') +      { +        info->homedir = _dbus_win_utf16_to_utf8 (user_info->usri1_home_dir, error); +        if (!info->homedir) +          goto out1; +      } +    else +      { +        _dbus_verbose("NetUserGetInfo() returned no home dir entry\n"); +        /* Not set, so use something random. */ +        info->homedir = _dbus_strdup ("\\"); +      } +  else +    { +      char *dc_string = _dbus_win_utf16_to_utf8(dc,error); +      _dbus_warn("NetUserGetInfo() failed with errorcode %d '%s', %s\n",ret,_dbus_lm_strerror(ret),dc_string); +      dbus_free(dc_string); +      /* Not set, so use something random. */ +      info->homedir = _dbus_strdup ("\\"); +    } + +  retval = TRUE; + +out1: +  if (dc != NULL) +    NetApiBufferFree (dc); +  if (user_info != NULL) +    NetApiBufferFree (user_info); + +  return retval; +#endif //DBUS_WINCE +} + +dbus_bool_t +fill_win_user_info_from_name (wchar_t      *wname, +                              DBusUserInfo *info, +                              DBusError    *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +	//TODO +#else +  dbus_bool_t retval = FALSE; +  PSID sid; +  wchar_t *wdomain; +  DWORD sid_length, wdomain_length; +  SID_NAME_USE use; + +  sid_length = 0; +  wdomain_length = 0; +  if (!LookupAccountNameW (NULL, wname, NULL, &sid_length, +                           NULL, &wdomain_length, &use) && +      GetLastError () != ERROR_INSUFFICIENT_BUFFER) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return FALSE; +    } + +  sid = dbus_malloc (sid_length); +  if (!sid) +    { +      _DBUS_SET_OOM (error); +      return FALSE; +    } + +  wdomain = dbus_new (wchar_t, wdomain_length); +  if (!wdomain) +    { +      _DBUS_SET_OOM (error); +      goto out0; +    } + +  if (!LookupAccountNameW (NULL, wname, sid, &sid_length, +                           wdomain, &wdomain_length, &use)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out1; +    } + +  if (!IsValidSid (sid)) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); +      goto out1; +    } + +  info->uid = _dbus_win_sid_to_uid_t (sid); + +  if (!fill_win_user_info_name_and_groups (wname, wdomain, info, error)) +    goto out1; + +  if (!fill_win_user_info_homedir (wname, wdomain, info, error)) +    goto out1; + +  retval = TRUE; + +out1: +  dbus_free (wdomain); +out0: +  dbus_free (sid); + +  return retval; +#endif //DBUS_WINCE +} + +dbus_bool_t +_dbus_win_sid_to_name_and_domain (dbus_uid_t uid, +                                  wchar_t  **wname, +                                  wchar_t  **wdomain, +                                  DBusError *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +	//TODO +#else +  PSID sid; +  DWORD wname_length, wdomain_length; +  SID_NAME_USE use; + +  if (!_dbus_uid_t_to_win_sid (uid, &sid)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return FALSE; +    } + +  wname_length = 0; +  wdomain_length = 0; +  if (!LookupAccountSidW (NULL, sid, NULL, &wname_length, +                          NULL, &wdomain_length, &use) && +      GetLastError () != ERROR_INSUFFICIENT_BUFFER) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out0; +    } + +  *wname = dbus_new (wchar_t, wname_length); +  if (!*wname) +    { +      _DBUS_SET_OOM (error); +      goto out0; +    } + +  *wdomain = dbus_new (wchar_t, wdomain_length); +  if (!*wdomain) +    { +      _DBUS_SET_OOM (error); +      goto out1; +    } + +  if (!LookupAccountSidW (NULL, sid, *wname, &wname_length, +                          *wdomain, &wdomain_length, &use)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out2; +    } + +  return TRUE; + +out2: +  dbus_free (*wdomain); +  *wdomain = NULL; +out1: +  dbus_free (*wname); +  *wname = NULL; +out0: +  LocalFree (sid); + +  return FALSE; +#endif //DBUS_WINCE +} + +dbus_bool_t +fill_win_user_info_from_uid (dbus_uid_t    uid, +                             DBusUserInfo *info, +                             DBusError    *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +	//TODO +#else +  PSID sid; +  dbus_bool_t retval = FALSE; +  wchar_t *wname, *wdomain; + +  info->uid = uid; + +  if (!_dbus_win_sid_to_name_and_domain (uid, &wname, &wdomain, error)) +    { +      _dbus_verbose("%s after _dbus_win_sid_to_name_and_domain\n",__FUNCTION__); +      return FALSE; +    } + +  if (!fill_win_user_info_name_and_groups (wname, wdomain, info, error)) +    { +      _dbus_verbose("%s after fill_win_user_info_name_and_groups\n",__FUNCTION__); +      goto out0; +    } + + +  if (!fill_win_user_info_homedir (wname, wdomain, info, error)) +    { +      _dbus_verbose("%s after fill_win_user_info_homedir\n",__FUNCTION__); +      goto out0; +    } + +  retval = TRUE; + +out0: +  dbus_free (wdomain); +  dbus_free (wname); + +  return retval; +#endif //DBUS_WINCE +} + + + + +void +_dbus_win_startup_winsock (void) +{ +  /* Straight from MSDN, deuglified */ + +  static dbus_bool_t beenhere = FALSE; + +  WORD wVersionRequested; +  WSADATA wsaData; +  int err; + +  if (beenhere) +    return; + +  wVersionRequested = MAKEWORD (2, 0); + +  err = WSAStartup (wVersionRequested, &wsaData); +  if (err != 0) +    { +      _dbus_assert_not_reached ("Could not initialize WinSock"); +      _dbus_abort (); +    } + +  /* Confirm that the WinSock DLL supports 2.0.  Note that if the DLL +   * supports versions greater than 2.0 in addition to 2.0, it will +   * still return 2.0 in wVersion since that is the version we +   * requested. +   */ +  if (LOBYTE (wsaData.wVersion) != 2 || +      HIBYTE (wsaData.wVersion) != 0) +    { +      _dbus_assert_not_reached ("No usable WinSock found"); +      _dbus_abort (); +    } + +  beenhere = TRUE; +} + + + + + + + + + +/************************************************************************ +  + UTF / string code +  + ************************************************************************/ + +/** + * Measure the message length without terminating nul  + */ +int _dbus_printf_string_upper_bound (const char *format, +                                     va_list args) +{ +  /* MSVCRT's vsnprintf semantics are a bit different */ +  /* The C library source in the Platform SDK indicates that this +   * would work, but alas, it doesn't. At least not on Windows +   * 2000. Presumably those sources correspond to the C library on +   * some newer or even future Windows version. +   * +    len = _vsnprintf (NULL, _DBUS_INT_MAX, format, args); +   */ +  char p[1024]; +  int len; +  len = vsnprintf (p, sizeof(p)-1, format, args); +  if (len == -1) // try again +    { +      char *p; +      p = malloc (strlen(format)*3); +      len = vsnprintf (p, sizeof(p)-1, format, args); +      free(p); +    } +  return len; +} + + +/** + * Returns the UTF-16 form of a UTF-8 string. The result should be + * freed with dbus_free() when no longer needed. + * + * @param str the UTF-8 string + * @param error return location for error code + */ +wchar_t * +_dbus_win_utf8_to_utf16 (const char *str, +                         DBusError  *error) +{ +  DBusString s; +  int n; +  wchar_t *retval; + +  _dbus_string_init_const (&s, str); + +  if (!_dbus_string_validate_utf8 (&s, 0, _dbus_string_get_length (&s))) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid UTF-8"); +      return NULL; +    } + +  n = MultiByteToWideChar (CP_UTF8, 0, str, -1, NULL, 0); + +  if (n == 0) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return NULL; +    } + +  retval = dbus_new (wchar_t, n); + +  if (!retval) +    { +      _DBUS_SET_OOM (error); +      return NULL; +    } + +  if (MultiByteToWideChar (CP_UTF8, 0, str, -1, retval, n) != n) +    { +      dbus_free (retval); +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "MultiByteToWideChar inconsistency"); +      return NULL; +    } + +  return retval; +} + +/** + * Returns the UTF-8 form of a UTF-16 string. The result should be + * freed with dbus_free() when no longer needed. + * + * @param str the UTF-16 string + * @param error return location for error code + */ +char * +_dbus_win_utf16_to_utf8 (const wchar_t *str, +                         DBusError     *error) +{ +  int n; +  char *retval; + +  n = WideCharToMultiByte (CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + +  if (n == 0) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return NULL; +    } + +  retval = dbus_malloc (n); + +  if (!retval) +    { +      _DBUS_SET_OOM (error); +      return NULL; +    } + +  if (WideCharToMultiByte (CP_UTF8, 0, str, -1, retval, n, NULL, NULL) != n) +    { +      dbus_free (retval); +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "WideCharToMultiByte inconsistency"); +      return NULL; +    } + +  return retval; +} + + + + + + +/************************************************************************ +  + uid ... <-> win sid functions +  + ************************************************************************/ + +dbus_bool_t +_dbus_win_account_to_sid (const wchar_t *waccount, +                          void      	 **ppsid, +                          DBusError 	  *error) +{ +  dbus_bool_t retval = FALSE; +  DWORD sid_length, wdomain_length; +  SID_NAME_USE use; +  wchar_t *wdomain; + +  *ppsid = NULL; + +  sid_length = 0; +  wdomain_length = 0; +  if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length, +                           NULL, &wdomain_length, &use) && +      GetLastError () != ERROR_INSUFFICIENT_BUFFER) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      return FALSE; +    } + +  *ppsid = dbus_malloc (sid_length); +  if (!*ppsid) +    { +      _DBUS_SET_OOM (error); +      return FALSE; +    } + +  wdomain = dbus_new (wchar_t, wdomain_length); +  if (!wdomain) +    { +      _DBUS_SET_OOM (error); +      goto out1; +    } + +  if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length, +                           wdomain, &wdomain_length, &use)) +    { +      _dbus_win_set_error_from_win_error (error, GetLastError ()); +      goto out2; +    } + +  if (!IsValidSid ((PSID) *ppsid)) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); +      goto out2; +    } + +  retval = TRUE; + +out2: +  dbus_free (wdomain); +out1: +  if (!retval) +    { +      dbus_free (*ppsid); +      *ppsid = NULL; +    } + +  return retval; +} + +static void +_sid_atom_cache_shutdown (void *unused) +{ +  DBusHashIter iter; +  _DBUS_LOCK (sid_atom_cache); +  _dbus_hash_iter_init (sid_atom_cache, &iter); +  while (_dbus_hash_iter_next (&iter)) +    { +      ATOM atom; +      atom = (ATOM) _dbus_hash_iter_get_value (&iter); +      GlobalDeleteAtom(atom); +      _dbus_hash_iter_remove_entry(&iter); +    } +  _DBUS_UNLOCK (sid_atom_cache); +  _dbus_hash_table_unref (sid_atom_cache); +  sid_atom_cache = NULL; +} + +/** + * Returns the 2-way associated dbus_uid_t form a SID. + * + * @param psid pointer to the SID + */ +dbus_uid_t +_dbus_win_sid_to_uid_t (PSID psid) +{ +  dbus_uid_t uid; +  dbus_uid_t olduid; +  char *string; +  ATOM atom; + +  if (!IsValidSid (psid)) +    { +      _dbus_verbose("%s invalid sid\n",__FUNCTION__); +      return DBUS_UID_UNSET; +    } +  if (!ConvertSidToStringSidA (psid, &string)) +    { +      _dbus_verbose("%s invalid sid\n",__FUNCTION__); +      return DBUS_UID_UNSET; +    } + +  atom = GlobalAddAtom(string); + +  if (atom == 0) +    { +      _dbus_verbose("%s GlobalAddAtom failed\n",__FUNCTION__); +      LocalFree (string); +      return DBUS_UID_UNSET; +    } + +  _DBUS_LOCK (sid_atom_cache); + +  if (sid_atom_cache == NULL) +    { +      sid_atom_cache = _dbus_hash_table_new (DBUS_HASH_ULONG, NULL, NULL); +      _dbus_register_shutdown_func (_sid_atom_cache_shutdown, NULL); +    } + +  uid = atom; +  olduid = (dbus_uid_t) _dbus_hash_table_lookup_ulong (sid_atom_cache, uid); + +  if (olduid) +    { +      _dbus_verbose("%s sid with id %i found in cache\n",__FUNCTION__, olduid); +      uid = olduid; +    } +  else +    { +      _dbus_hash_table_insert_ulong (sid_atom_cache, uid, (void*) uid); +      _dbus_verbose("%s sid %s added with uid %i to cache\n",__FUNCTION__, string, uid); +    } + +  _DBUS_UNLOCK (sid_atom_cache); + +  return uid; +} + +dbus_bool_t  _dbus_uid_t_to_win_sid (dbus_uid_t uid, PSID *ppsid) +{ +  void* atom; +  char string[255]; + +  atom = _dbus_hash_table_lookup_ulong (sid_atom_cache, uid); +  if (atom == NULL) +    { +      _dbus_verbose("%s uid %i not found in cache\n",__FUNCTION__,uid); +      return FALSE; +    } +  memset( string, '.', sizeof(string) ); +  if (!GlobalGetAtomNameA( (ATOM) atom, string, 255 )) +    { +      _dbus_verbose("%s uid %i not found in cache\n",__FUNCTION__, uid); +      return FALSE; +    } +  if (!ConvertStringSidToSidA(string, ppsid)) +    { +      _dbus_verbose("%s could not convert %s into sid \n",__FUNCTION__, string); +      return FALSE; +    } +  _dbus_verbose("%s converted %s into sid \n",__FUNCTION__, string); +  return TRUE; +} + + +/** @} end of sysdeps-win */ + + +/** Gets our UID + * @returns process UID + */ +dbus_uid_t +_dbus_getuid(void) +{ +  dbus_uid_t retval = DBUS_UID_UNSET; +  HANDLE process_token = NULL; +  TOKEN_USER *token_user = NULL; +  DWORD n; + +  if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token)) +    _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ()); +  else if ((!GetTokenInformation (process_token, TokenUser, NULL, 0, &n) +            && GetLastError () != ERROR_INSUFFICIENT_BUFFER) +           || (token_user = alloca (n)) == NULL +           || !GetTokenInformation (process_token, TokenUser, token_user, n, &n)) +    _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ()); +  else +    retval = _dbus_win_sid_to_uid_t (token_user->User.Sid); + +  if (process_token != NULL) +    CloseHandle (process_token); + +  _dbus_verbose("_dbus_getuid() returns %d\n",retval); +  return retval; +} + +#ifdef DBUS_BUILD_TESTS +/** Gets our GID + * @returns process GID + */ +dbus_gid_t +_dbus_getgid (void) +{ +  dbus_gid_t retval = DBUS_GID_UNSET; +  HANDLE process_token = NULL; +  TOKEN_PRIMARY_GROUP *token_primary_group = NULL; +  DWORD n; + +  if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token)) +    _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ()); +  else if ((!GetTokenInformation (process_token, TokenPrimaryGroup, +                                  NULL, 0, &n) && +            GetLastError () != ERROR_INSUFFICIENT_BUFFER) || +           (token_primary_group = alloca (n)) == NULL || +           !GetTokenInformation (process_token, TokenPrimaryGroup, +                                 token_primary_group, n, &n)) +    _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ()); +  else +    retval = _dbus_win_sid_to_uid_t (token_primary_group->PrimaryGroup); + +  if (process_token != NULL) +    CloseHandle (process_token); + +  return retval; +} + +#if 0 +dbus_bool_t +_dbus_domain_test (const char *test_data_dir) +{ +  if (!_dbus_test_oom_handling ("spawn_nonexistent", +                                check_spawn_nonexistent, +                                NULL)) +    return FALSE; +} + +#endif + +#endif //DBUS_BUILD_TESTS + +/************************************************************************ +  + pipes +  + ************************************************************************/ + +/** + * Creates a full-duplex pipe (as in socketpair()). + * Sets both ends of the pipe nonblocking. + * + * @todo libdbus only uses this for the debug-pipe server, so in + * principle it could be in dbus-sysdeps-util.c, except that + * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the + * debug-pipe server is used. + *  + * @param fd1 return location for one end + * @param fd2 return location for the other end + * @param blocking #TRUE if pipe should be blocking + * @param error error return + * @returns #FALSE on failure (if error is set) + */ +dbus_bool_t +_dbus_full_duplex_pipe (int        *fd1, +                        int        *fd2, +                        dbus_bool_t blocking, +                        DBusError  *error) +{ +  SOCKET temp, socket1 = -1, socket2 = -1; +  struct sockaddr_in saddr; +  int len; +  u_long arg; +  fd_set read_set, write_set; +  struct timeval tv; +  DBusSocket sock; + + +  _dbus_win_startup_winsock (); + +  temp = socket (AF_INET, SOCK_STREAM, 0); +  if (temp == INVALID_SOCKET) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out0; +    } + +  arg = 1; +  if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out0; +    } + +  _DBUS_ZERO (saddr); +  saddr.sin_family = AF_INET; +  saddr.sin_port = 0; +  saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + +  if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out0; +    } + +  if (listen (temp, 1) == SOCKET_ERROR) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out0; +    } + +  len = sizeof (saddr); +  if (getsockname (temp, (struct sockaddr *)&saddr, &len)) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out0; +    } + +  socket1 = socket (AF_INET, SOCK_STREAM, 0); +  if (socket1 == INVALID_SOCKET) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out0; +    } + +  arg = 1; +  if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out1; +    } + +  if (connect (socket1, (struct sockaddr  *)&saddr, len) != SOCKET_ERROR || +      WSAGetLastError () != WSAEWOULDBLOCK) +    { +      dbus_set_error_const (error, DBUS_ERROR_FAILED, +                            "_dbus_full_duplex_pipe socketpair() emulation failed"); +      goto out1; +    } + +  FD_ZERO (&read_set); +  FD_SET (temp, &read_set); + +  tv.tv_sec = 0; +  tv.tv_usec = 0; + +  if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out1; +    } + +  _dbus_assert (FD_ISSET (temp, &read_set)); + +  socket2 = accept (temp, (struct sockaddr *) &saddr, &len); +  if (socket2 == INVALID_SOCKET) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out1; +    } + +  FD_ZERO (&write_set); +  FD_SET (socket1, &write_set); + +  tv.tv_sec = 0; +  tv.tv_usec = 0; + +  if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) +    { +      DBUS_SOCKET_SET_ERRNO (); +      goto out2; +    } + +  _dbus_assert (FD_ISSET (socket1, &write_set)); + +  if (blocking) +    { +      arg = 0; +      if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) +        { +          DBUS_SOCKET_SET_ERRNO (); +          goto out2; +        } + +      arg = 0; +      if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) +        { +          DBUS_SOCKET_SET_ERRNO (); +          goto out2; +        } +    } +  else +    { +      arg = 1; +      if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) +        { +          DBUS_SOCKET_SET_ERRNO (); +          goto out2; +        } +    } + +  sock.fd = socket1; +  *fd1 = _dbus_socket_to_handle (&sock); +  sock.fd = socket2; +  *fd2 = _dbus_socket_to_handle (&sock); + +  _dbus_verbose ("full-duplex pipe %d:%d <-> %d:%d\n", +                 *fd1, socket1, *fd2, socket2); + +  closesocket (temp); + +  return TRUE; + +out2: +  closesocket (socket2); +out1: +  closesocket (socket1); +out0: +  closesocket (temp); + +  dbus_set_error (error, _dbus_error_from_errno (errno), +                  "Could not setup socket pair: %s", +                  _dbus_strerror (errno)); + +  return FALSE; +} + +/** + * Wrapper for poll(). + * + * @param fds the file descriptors to poll + * @param n_fds number of descriptors in the array + * @param timeout_milliseconds timeout or -1 for infinite + * @returns numbers of fds with revents, or <0 on error + */ +#define USE_CHRIS_IMPL 0 +#if USE_CHRIS_IMPL +int +_dbus_poll (DBusPollFD *fds, +            int         n_fds, +            int         timeout_milliseconds) +{ +#define DBUS_POLL_CHAR_BUFFER_SIZE 2000 +  char msg[DBUS_POLL_CHAR_BUFFER_SIZE]; +  char *msgp; + +  int ret = 0; +  int i; +  struct timeval tv; +  int ready; + +#define DBUS_STACK_WSAEVENTS 256 +  WSAEVENT eventsOnStack[DBUS_STACK_WSAEVENTS]; +  WSAEVENT *pEvents = NULL; +  if (n_fds > DBUS_STACK_WSAEVENTS) +    pEvents = calloc(sizeof(WSAEVENT), n_fds); +  else +    pEvents = eventsOnStack; + +  _dbus_lock_sockets(); + +#ifdef DBUS_ENABLE_VERBOSE_MODE +  msgp = msg; +  msgp += sprintf (msgp, "WSAEventSelect: to=%d\n\t", timeout_milliseconds); +  for (i = 0; i < n_fds; i++) +    { +      static dbus_bool_t warned = FALSE; +      DBusSocket *s; +      DBusPollFD *fdp = &fds[i]; + +      _dbus_handle_to_socket_unlocked(fdp->fd, &s);   + +      if (s->is_used == 0) +        { +          _dbus_warn ("no valid socket"); +          warned = TRUE; +        } + +      if (fdp->events & _DBUS_POLLIN) +        msgp += sprintf (msgp, "R:%d ", s->fd); + +      if (fdp->events & _DBUS_POLLOUT) +        msgp += sprintf (msgp, "W:%d ", s->fd); + +      msgp += sprintf (msgp, "E:%d\n\t", s->fd); + +      // FIXME: more robust code for long  msg +      //        create on heap when msg[] becomes too small +      if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE) +        { +          _dbus_assert_not_reached ("buffer overflow in _dbus_poll"); +        } +    } + +  msgp += sprintf (msgp, "\n"); +  _dbus_verbose ("%s",msg); +#endif +  for (i = 0; i < n_fds; i++) +    { +      DBusSocket *s; +      DBusPollFD *fdp = &fds[i]; +      WSAEVENT ev; +      long lNetworkEvents = FD_OOB; + +      _dbus_handle_to_socket_unlocked(fdp->fd, &s);  + +      if (s->is_used == 0) +        continue; + +      ev = WSACreateEvent(); + +      if (fdp->events & _DBUS_POLLIN) +        lNetworkEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; + +      if (fdp->events & _DBUS_POLLOUT) +        lNetworkEvents |= FD_WRITE | FD_CONNECT; + +      WSAEventSelect(s->fd, ev, lNetworkEvents); + +      pEvents[i] = ev; +    } + +  _dbus_unlock_sockets(); + +  ready = WSAWaitForMultipleEvents (n_fds, pEvents, FALSE, timeout_milliseconds, FALSE); + +  if (DBUS_SOCKET_API_RETURNS_ERROR (ready)) +    { +      DBUS_SOCKET_SET_ERRNO (); +      if (errno != EWOULDBLOCK) +        _dbus_verbose ("WSAWaitForMultipleEvents: failed: %s\n", _dbus_strerror (errno)); +      ret = -1; +    } +  else if (ready == WSA_WAIT_TIMEOUT) +    { +      _dbus_verbose ("WSAWaitForMultipleEvents: WSA_WAIT_TIMEOUT\n"); +      ret = 0; +    } +  else if (ready >= WSA_WAIT_EVENT_0 && ready < (int)(WSA_WAIT_EVENT_0 + n_fds)) +    { +      msgp = msg; +      msgp += sprintf (msgp, "WSAWaitForMultipleEvents: =%d\n\t", ready); + +      _dbus_lock_sockets(); +      for (i = 0; i < n_fds; i++) +        { +          DBusSocket *s; +          DBusPollFD *fdp = &fds[i]; +          WSANETWORKEVENTS ne; + +          _dbus_handle_to_socket_unlocked(fdp->fd, &s);  + +          fdp->revents = 0; + +          WSAEnumNetworkEvents(s->fd, pEvents[i], &ne); + +          if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) +            fdp->revents |= _DBUS_POLLIN; + +          if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT)) +            fdp->revents |= _DBUS_POLLOUT; + +          if (ne.lNetworkEvents & (FD_OOB)) +            fdp->revents |= _DBUS_POLLERR; + +          if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) +              msgp += sprintf (msgp, "R:%d ", s->fd); + +          if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT)) +              msgp += sprintf (msgp, "W:%d ", s->fd); + +          if (ne.lNetworkEvents & (FD_OOB)) +              msgp += sprintf (msgp, "E:%d ", s->fd); + +          msgp += sprintf (msgp, "lNetworkEvents:%d ", ne.lNetworkEvents); + +          if(ne.lNetworkEvents) +            ret++; + +          WSAEventSelect(s->fd, pEvents[i], 0); +        } +      _dbus_unlock_sockets(); + +      msgp += sprintf (msgp, "\n"); +      _dbus_verbose ("%s",msg); +    } +  else +    { +      _dbus_verbose ("WSAWaitForMultipleEvents: failed for unknown reason!"); +      ret = -1; +    } + +  for(i = 0; i < n_fds; i++) +    { +      WSACloseEvent(pEvents[i]); +    } + +  if (n_fds > DBUS_STACK_WSAEVENTS) +    free(pEvents); + +  return ret; +} + +#else   // USE_CHRIS_IMPL + +int +_dbus_poll (DBusPollFD *fds, +            int         n_fds, +            int         timeout_milliseconds) +{ +#define DBUS_POLL_CHAR_BUFFER_SIZE 2000 +  char msg[DBUS_POLL_CHAR_BUFFER_SIZE]; +  char *msgp; + +  fd_set read_set, write_set, err_set; +  int max_fd = 0; +  int i; +  struct timeval tv; +  int ready; + +  FD_ZERO (&read_set); +  FD_ZERO (&write_set); +  FD_ZERO (&err_set); + +  _dbus_lock_sockets(); + +#ifdef DBUS_ENABLE_VERBOSE_MODE +  msgp = msg; +  msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds); +  for (i = 0; i < n_fds; i++) +    { +      static dbus_bool_t warned = FALSE; +      DBusSocket *s; +      DBusPollFD *fdp = &fds[i]; + +      _dbus_handle_to_socket_unlocked(fdp->fd, &s);   + +      if (s->is_used == 0) +        { +          _dbus_warn ("no valid socket"); +          warned = TRUE; +        } + +      if (fdp->events & _DBUS_POLLIN) +        msgp += sprintf (msgp, "R:%d ", s->fd); + +      if (fdp->events & _DBUS_POLLOUT) +        msgp += sprintf (msgp, "W:%d ", s->fd); + +      msgp += sprintf (msgp, "E:%d\n\t", s->fd); + +      // FIXME: more robust code for long  msg +      //        create on heap when msg[] becomes too small +      if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE) +        { +          _dbus_assert_not_reached ("buffer overflow in _dbus_poll"); +        } +    } + +  msgp += sprintf (msgp, "\n"); +  _dbus_verbose ("%s",msg); +#endif +  for (i = 0; i < n_fds; i++) +    { +      DBusSocket *s; +      DBusPollFD *fdp = &fds[i]; + +      _dbus_handle_to_socket_unlocked(fdp->fd, &s);  + +      if (s->is_used != 1) +        continue; + +      if (fdp->events & _DBUS_POLLIN) +        FD_SET (s->fd, &read_set); + +      if (fdp->events & _DBUS_POLLOUT) +        FD_SET (s->fd, &write_set); + +      FD_SET (s->fd, &err_set); + +      max_fd = MAX (max_fd, s->fd); +    } + +  _dbus_unlock_sockets(); + +  tv.tv_sec = timeout_milliseconds / 1000; +  tv.tv_usec = (timeout_milliseconds % 1000) * 1000; + +  ready = select (max_fd + 1, &read_set, &write_set, &err_set, +                  timeout_milliseconds < 0 ? NULL : &tv); + +  if (DBUS_SOCKET_API_RETURNS_ERROR (ready)) +    { +      DBUS_SOCKET_SET_ERRNO (); +      if (errno != EWOULDBLOCK) +        _dbus_verbose ("select: failed: %s\n", _dbus_strerror (errno)); +    } +  else if (ready == 0) +    _dbus_verbose ("select: = 0\n"); +  else +    if (ready > 0) +      { +#ifdef DBUS_ENABLE_VERBOSE_MODE +        msgp = msg; +        msgp += sprintf (msgp, "select: = %d:\n\t", ready); +        _dbus_lock_sockets(); +        for (i = 0; i < n_fds; i++) +          { +            DBusSocket *s; +            DBusPollFD *fdp = &fds[i]; + +            _dbus_handle_to_socket_unlocked(fdp->fd, &s);  + +            if (FD_ISSET (s->fd, &read_set)) +              msgp += sprintf (msgp, "R:%d ", s->fd); + +            if (FD_ISSET (s->fd, &write_set)) +              msgp += sprintf (msgp, "W:%d ", s->fd); + +            if (FD_ISSET (s->fd, &err_set)) +              msgp += sprintf (msgp, "E:%d\n\t", s->fd); +          } +        msgp += sprintf (msgp, "\n"); +        _dbus_verbose ("%s",msg); +#endif + +        for (i = 0; i < n_fds; i++) +          { +            DBusSocket *s; +            DBusPollFD *fdp = &fds[i]; + +            _dbus_handle_to_socket_unlocked(fdp->fd, &s);  + +            fdp->revents = 0; + +            if (FD_ISSET (s->fd, &read_set)) +              fdp->revents |= _DBUS_POLLIN; + +            if (FD_ISSET (s->fd, &write_set)) +              fdp->revents |= _DBUS_POLLOUT; + +            if (FD_ISSET (s->fd, &err_set)) +              fdp->revents |= _DBUS_POLLERR; +          } +        _dbus_unlock_sockets(); +      } +  return ready; +} +#endif  // USE_CHRIS_IMPL + + +/************************************************************************ +  + error handling +  + ************************************************************************/ + + +/** + * Assigns an error name and message corresponding to a Win32 error + * code to a DBusError. Does nothing if error is #NULL. + * + * @param error the error. + * @param code the Win32 error code + */ +void +_dbus_win_set_error_from_win_error (DBusError *error, +                                    int        code) +{ +  char *msg; + +  /* As we want the English message, use the A API */ +  FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | +                  FORMAT_MESSAGE_IGNORE_INSERTS | +                  FORMAT_MESSAGE_FROM_SYSTEM, +                  NULL, code, MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US), +                  (LPTSTR) &msg, 0, NULL); +  if (msg) +    { +      char *msg_copy; + +      msg_copy = dbus_malloc (strlen (msg)); +      strcpy (msg_copy, msg); +      LocalFree (msg); + +      dbus_set_error (error, "Win32 error", "%s", msg_copy); +    } +  else +    dbus_set_error_const (error, "Win32 error", "Unknown error code or FormatMessage failed"); +} + +void +_dbus_win_warn_win_error (const char *message, +                          int         code) +{ +  DBusError error; + +  dbus_error_init (&error); +  _dbus_win_set_error_from_win_error (&error, code); +  _dbus_warn ("%s: %s\n", message, error.message); +  dbus_error_free (&error); +} + +/** + * A wrapper around strerror() because some platforms + * may be lame and not have strerror(). + * + * @param error_number errno. + * @returns error description. + */ +const char* +_dbus_strerror (int error_number) +{ +#ifdef DBUS_WINCE +  // TODO +  return "unknown"; +#else +  const char *msg; + +  switch (error_number) +    { +    case WSAEINTR: +      return "Interrupted function call"; +    case WSAEACCES: +      return "Permission denied"; +    case WSAEFAULT: +      return "Bad address"; +    case WSAEINVAL: +      return "Invalid argument"; +    case WSAEMFILE: +      return "Too many open files"; +    case WSAEWOULDBLOCK: +      return "Resource temporarily unavailable"; +    case WSAEINPROGRESS: +      return "Operation now in progress"; +    case WSAEALREADY: +      return "Operation already in progress"; +    case WSAENOTSOCK: +      return "Socket operation on nonsocket"; +    case WSAEDESTADDRREQ: +      return "Destination address required"; +    case WSAEMSGSIZE: +      return "Message too long"; +    case WSAEPROTOTYPE: +      return "Protocol wrong type for socket"; +    case WSAENOPROTOOPT: +      return "Bad protocol option"; +    case WSAEPROTONOSUPPORT: +      return "Protocol not supported"; +    case WSAESOCKTNOSUPPORT: +      return "Socket type not supported"; +    case WSAEOPNOTSUPP: +      return "Operation not supported"; +    case WSAEPFNOSUPPORT: +      return "Protocol family not supported"; +    case WSAEAFNOSUPPORT: +      return "Address family not supported by protocol family"; +    case WSAEADDRINUSE: +      return "Address already in use"; +    case WSAEADDRNOTAVAIL: +      return "Cannot assign requested address"; +    case WSAENETDOWN: +      return "Network is down"; +    case WSAENETUNREACH: +      return "Network is unreachable"; +    case WSAENETRESET: +      return "Network dropped connection on reset"; +    case WSAECONNABORTED: +      return "Software caused connection abort"; +    case WSAECONNRESET: +      return "Connection reset by peer"; +    case WSAENOBUFS: +      return "No buffer space available"; +    case WSAEISCONN: +      return "Socket is already connected"; +    case WSAENOTCONN: +      return "Socket is not connected"; +    case WSAESHUTDOWN: +      return "Cannot send after socket shutdown"; +    case WSAETIMEDOUT: +      return "Connection timed out"; +    case WSAECONNREFUSED: +      return "Connection refused"; +    case WSAEHOSTDOWN: +      return "Host is down"; +    case WSAEHOSTUNREACH: +      return "No route to host"; +    case WSAEPROCLIM: +      return "Too many processes"; +    case WSAEDISCON: +      return "Graceful shutdown in progress"; +    case WSATYPE_NOT_FOUND: +      return "Class type not found"; +    case WSAHOST_NOT_FOUND: +      return "Host not found"; +    case WSATRY_AGAIN: +      return "Nonauthoritative host not found"; +    case WSANO_RECOVERY: +      return "This is a nonrecoverable error"; +    case WSANO_DATA: +      return "Valid name, no data record of requested type"; +    case WSA_INVALID_HANDLE: +      return "Specified event object handle is invalid"; +    case WSA_INVALID_PARAMETER: +      return "One or more parameters are invalid"; +    case WSA_IO_INCOMPLETE: +      return "Overlapped I/O event object not in signaled state"; +    case WSA_IO_PENDING: +      return "Overlapped operations will complete later"; +    case WSA_NOT_ENOUGH_MEMORY: +      return "Insufficient memory available"; +    case WSA_OPERATION_ABORTED: +      return "Overlapped operation aborted"; +#ifdef WSAINVALIDPROCTABLE + +    case WSAINVALIDPROCTABLE: +      return "Invalid procedure table from service provider"; +#endif +#ifdef WSAINVALIDPROVIDER + +    case WSAINVALIDPROVIDER: +      return "Invalid service provider version number"; +#endif +#ifdef WSAPROVIDERFAILEDINIT + +    case WSAPROVIDERFAILEDINIT: +      return "Unable to initialize a service provider"; +#endif + +    case WSASYSCALLFAILURE: +      return "System call failure"; +    } +  msg = strerror (error_number); +  if (msg == NULL) +    msg = "unknown"; + +  return msg; +#endif //DBUS_WINCE +} + + + +/* lan manager error codes */ +const char* +_dbus_lm_strerror(int error_number) +{ +#ifdef DBUS_WINCE +  // TODO +  return "unknown"; +#else +  const char *msg; +  switch (error_number) +    { +    case NERR_NetNotStarted: +      return "The workstation driver is not installed."; +    case NERR_UnknownServer: +      return "The server could not be located."; +    case NERR_ShareMem: +      return "An internal error occurred. The network cannot access a shared memory segment."; +    case NERR_NoNetworkResource: +      return "A network resource shortage occurred."; +    case NERR_RemoteOnly: +      return "This operation is not supported on workstations."; +    case NERR_DevNotRedirected: +      return "The device is not connected."; +    case NERR_ServerNotStarted: +      return "The Server service is not started."; +    case NERR_ItemNotFound: +      return "The queue is empty."; +    case NERR_UnknownDevDir: +      return "The device or directory does not exist."; +    case NERR_RedirectedPath: +      return "The operation is invalid on a redirected resource."; +    case NERR_DuplicateShare: +      return "The name has already been shared."; +    case NERR_NoRoom: +      return "The server is currently out of the requested resource."; +    case NERR_TooManyItems: +      return "Requested addition of items exceeds the maximum allowed."; +    case NERR_InvalidMaxUsers: +      return "The Peer service supports only two simultaneous users."; +    case NERR_BufTooSmall: +      return "The API return buffer is too small."; +    case NERR_RemoteErr: +      return "A remote API error occurred."; +    case NERR_LanmanIniError: +      return "An error occurred when opening or reading the configuration file."; +    case NERR_NetworkError: +      return "A general network error occurred."; +    case NERR_WkstaInconsistentState: +      return "The Workstation service is in an inconsistent state. Restart the computer before restarting the Workstation service."; +    case NERR_WkstaNotStarted: +      return "The Workstation service has not been started."; +    case NERR_BrowserNotStarted: +      return "The requested information is not available."; +    case NERR_InternalError: +      return "An internal error occurred."; +    case NERR_BadTransactConfig: +      return "The server is not configured for transactions."; +    case NERR_InvalidAPI: +      return "The requested API is not supported on the remote server."; +    case NERR_BadEventName: +      return "The event name is invalid."; +    case NERR_DupNameReboot: +      return "The computer name already exists on the network. Change it and restart the computer."; +    case NERR_CfgCompNotFound: +      return "The specified component could not be found in the configuration information."; +    case NERR_CfgParamNotFound: +      return "The specified parameter could not be found in the configuration information."; +    case NERR_LineTooLong: +      return "A line in the configuration file is too long."; +    case NERR_QNotFound: +      return "The printer does not exist."; +    case NERR_JobNotFound: +      return "The print job does not exist."; +    case NERR_DestNotFound: +      return "The printer destination cannot be found."; +    case NERR_DestExists: +      return "The printer destination already exists."; +    case NERR_QExists: +      return "The printer queue already exists."; +    case NERR_QNoRoom: +      return "No more printers can be added."; +    case NERR_JobNoRoom: +      return "No more print jobs can be added."; +    case NERR_DestNoRoom: +      return "No more printer destinations can be added."; +    case NERR_DestIdle: +      return "This printer destination is idle and cannot accept control operations."; +    case NERR_DestInvalidOp: +      return "This printer destination request contains an invalid control function."; +    case NERR_ProcNoRespond: +      return "The print processor is not responding."; +    case NERR_SpoolerNotLoaded: +      return "The spooler is not running."; +    case NERR_DestInvalidState: +      return "This operation cannot be performed on the print destination in its current state."; +    case NERR_QInvalidState: +      return "This operation cannot be performed on the printer queue in its current state."; +    case NERR_JobInvalidState: +      return "This operation cannot be performed on the print job in its current state."; +    case NERR_SpoolNoMemory: +      return "A spooler memory allocation failure occurred."; +    case NERR_DriverNotFound: +      return "The device driver does not exist."; +    case NERR_DataTypeInvalid: +      return "The data type is not supported by the print processor."; +    case NERR_ProcNotFound: +      return "The print processor is not installed."; +    case NERR_ServiceTableLocked: +      return "The service database is locked."; +    case NERR_ServiceTableFull: +      return "The service table is full."; +    case NERR_ServiceInstalled: +      return "The requested service has already been started."; +    case NERR_ServiceEntryLocked: +      return "The service does not respond to control actions."; +    case NERR_ServiceNotInstalled: +      return "The service has not been started."; +    case NERR_BadServiceName: +      return "The service name is invalid."; +    case NERR_ServiceCtlTimeout: +      return "The service is not responding to the control function."; +    case NERR_ServiceCtlBusy: +      return "The service control is busy."; +    case NERR_BadServiceProgName: +      return "The configuration file contains an invalid service program name."; +    case NERR_ServiceNotCtrl: +      return "The service could not be controlled in its present state."; +    case NERR_ServiceKillProc: +      return "The service ended abnormally."; +    case NERR_ServiceCtlNotValid: +      return "The requested pause or stop is not valid for this service."; +    case NERR_NotInDispatchTbl: +      return "The service control dispatcher could not find the service name in the dispatch table."; +    case NERR_BadControlRecv: +      return "The service control dispatcher pipe read failed."; +    case NERR_ServiceNotStarting: +      return "A thread for the new service could not be created."; +    case NERR_AlreadyLoggedOn: +      return "This workstation is already logged on to the local-area network."; +    case NERR_NotLoggedOn: +      return "The workstation is not logged on to the local-area network."; +    case NERR_BadUsername: +      return "The user name or group name parameter is invalid."; +    case NERR_BadPassword: +      return "The password parameter is invalid."; +    case NERR_UnableToAddName_W: +      return "@W The logon processor did not add the message alias."; +    case NERR_UnableToAddName_F: +      return "The logon processor did not add the message alias."; +    case NERR_UnableToDelName_W: +      return "@W The logoff processor did not delete the message alias."; +    case NERR_UnableToDelName_F: +      return "The logoff processor did not delete the message alias."; +    case NERR_LogonsPaused: +      return "Network logons are paused."; +    case NERR_LogonServerConflict: +      return "A centralized logon-server conflict occurred."; +    case NERR_LogonNoUserPath: +      return "The server is configured without a valid user path."; +    case NERR_LogonScriptError: +      return "An error occurred while loading or running the logon script."; +    case NERR_StandaloneLogon: +      return "The logon server was not specified. Your computer will be logged on as STANDALONE."; +    case NERR_LogonServerNotFound: +      return "The logon server could not be found."; +    case NERR_LogonDomainExists: +      return "There is already a logon domain for this computer."; +    case NERR_NonValidatedLogon: +      return "The logon server could not validate the logon."; +    case NERR_ACFNotFound: +      return "The security database could not be found."; +    case NERR_GroupNotFound: +      return "The group name could not be found."; +    case NERR_UserNotFound: +      return "The user name could not be found."; +    case NERR_ResourceNotFound: +      return "The resource name could not be found."; +    case NERR_GroupExists: +      return "The group already exists."; +    case NERR_UserExists: +      return "The user account already exists."; +    case NERR_ResourceExists: +      return "The resource permission list already exists."; +    case NERR_NotPrimary: +      return "This operation is only allowed on the primary domain controller of the domain."; +    case NERR_ACFNotLoaded: +      return "The security database has not been started."; +    case NERR_ACFNoRoom: +      return "There are too many names in the user accounts database."; +    case NERR_ACFFileIOFail: +      return "A disk I/O failure occurred."; +    case NERR_ACFTooManyLists: +      return "The limit of 64 entries per resource was exceeded."; +    case NERR_UserLogon: +      return "Deleting a user with a session is not allowed."; +    case NERR_ACFNoParent: +      return "The parent directory could not be located."; +    case NERR_CanNotGrowSegment: +      return "Unable to add to the security database session cache segment."; +    case NERR_SpeGroupOp: +      return "This operation is not allowed on this special group."; +    case NERR_NotInCache: +      return "This user is not cached in user accounts database session cache."; +    case NERR_UserInGroup: +      return "The user already belongs to this group."; +    case NERR_UserNotInGroup: +      return "The user does not belong to this group."; +    case NERR_AccountUndefined: +      return "This user account is undefined."; +    case NERR_AccountExpired: +      return "This user account has expired."; +    case NERR_InvalidWorkstation: +      return "The user is not allowed to log on from this workstation."; +    case NERR_InvalidLogonHours: +      return "The user is not allowed to log on at this time."; +    case NERR_PasswordExpired: +      return "The password of this user has expired."; +    case NERR_PasswordCantChange: +      return "The password of this user cannot change."; +    case NERR_PasswordHistConflict: +      return "This password cannot be used now."; +    case NERR_PasswordTooShort: +      return "The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements."; +    case NERR_PasswordTooRecent: +      return "The password of this user is too recent to change."; +    case NERR_InvalidDatabase: +      return "The security database is corrupted."; +    case NERR_DatabaseUpToDate: +      return "No updates are necessary to this replicant network/local security database."; +    case NERR_SyncRequired: +      return "This replicant database is outdated; synchronization is required."; +    case NERR_UseNotFound: +      return "The network connection could not be found."; +    case NERR_BadAsgType: +      return "This asg_type is invalid."; +    case NERR_DeviceIsShared: +      return "This device is currently being shared."; +    case NERR_NoComputerName: +      return "The computer name could not be added as a message alias. The name may already exist on the network."; +    case NERR_MsgAlreadyStarted: +      return "The Messenger service is already started."; +    case NERR_MsgInitFailed: +      return "The Messenger service failed to start."; +    case NERR_NameNotFound: +      return "The message alias could not be found on the network."; +    case NERR_AlreadyForwarded: +      return "This message alias has already been forwarded."; +    case NERR_AddForwarded: +      return "This message alias has been added but is still forwarded."; +    case NERR_AlreadyExists: +      return "This message alias already exists locally."; +    case NERR_TooManyNames: +      return "The maximum number of added message aliases has been exceeded."; +    case NERR_DelComputerName: +      return "The computer name could not be deleted."; +    case NERR_LocalForward: +      return "Messages cannot be forwarded back to the same workstation."; +    case NERR_GrpMsgProcessor: +      return "An error occurred in the domain message processor."; +    case NERR_PausedRemote: +      return "The message was sent, but the recipient has paused the Messenger service."; +    case NERR_BadReceive: +      return "The message was sent but not received."; +    case NERR_NameInUse: +      return "The message alias is currently in use. Try again later."; +    case NERR_MsgNotStarted: +      return "The Messenger service has not been started."; +    case NERR_NotLocalName: +      return "The name is not on the local computer."; +    case NERR_NoForwardName: +      return "The forwarded message alias could not be found on the network."; +    case NERR_RemoteFull: +      return "The message alias table on the remote station is full."; +    case NERR_NameNotForwarded: +      return "Messages for this alias are not currently being forwarded."; +    case NERR_TruncatedBroadcast: +      return "The broadcast message was truncated."; +    case NERR_InvalidDevice: +      return "This is an invalid device name."; +    case NERR_WriteFault: +      return "A write fault occurred."; +    case NERR_DuplicateName: +      return "A duplicate message alias exists on the network."; +    case NERR_DeleteLater: +      return "@W This message alias will be deleted later."; +    case NERR_IncompleteDel: +      return "The message alias was not successfully deleted from all networks."; +    case NERR_MultipleNets: +      return "This operation is not supported on computers with multiple networks."; +    case NERR_NetNameNotFound: +      return "This shared resource does not exist."; +    case NERR_DeviceNotShared: +      return "This device is not shared."; +    case NERR_ClientNameNotFound: +      return "A session does not exist with that computer name."; +    case NERR_FileIdNotFound: +      return "There is not an open file with that identification number."; +    case NERR_ExecFailure: +      return "A failure occurred when executing a remote administration command."; +    case NERR_TmpFile: +      return "A failure occurred when opening a remote temporary file."; +    case NERR_TooMuchData: +      return "The data returned from a remote administration command has been truncated to 64K."; +    case NERR_DeviceShareConflict: +      return "This device cannot be shared as both a spooled and a non-spooled resource."; +    case NERR_BrowserTableIncomplete: +      return "The information in the list of servers may be incorrect."; +    case NERR_NotLocalDomain: +      return "The computer is not active in this domain."; +#ifdef NERR_IsDfsShare + +    case NERR_IsDfsShare: +      return "The share must be removed from the Distributed File System before it can be deleted."; +#endif + +    case NERR_DevInvalidOpCode: +      return "The operation is invalid for this device."; +    case NERR_DevNotFound: +      return "This device cannot be shared."; +    case NERR_DevNotOpen: +      return "This device was not open."; +    case NERR_BadQueueDevString: +      return "This device name list is invalid."; +    case NERR_BadQueuePriority: +      return "The queue priority is invalid."; +    case NERR_NoCommDevs: +      return "There are no shared communication devices."; +    case NERR_QueueNotFound: +      return "The queue you specified does not exist."; +    case NERR_BadDevString: +      return "This list of devices is invalid."; +    case NERR_BadDev: +      return "The requested device is invalid."; +    case NERR_InUseBySpooler: +      return "This device is already in use by the spooler."; +    case NERR_CommDevInUse: +      return "This device is already in use as a communication device."; +    case NERR_InvalidComputer: +      return "This computer name is invalid."; +    case NERR_MaxLenExceeded: +      return "The string and prefix specified are too long."; +    case NERR_BadComponent: +      return "This path component is invalid."; +    case NERR_CantType: +      return "Could not determine the type of input."; +    case NERR_TooManyEntries: +      return "The buffer for types is not big enough."; +    case NERR_ProfileFileTooBig: +      return "Profile files cannot exceed 64K."; +    case NERR_ProfileOffset: +      return "The start offset is out of range."; +    case NERR_ProfileCleanup: +      return "The system cannot delete current connections to network resources."; +    case NERR_ProfileUnknownCmd: +      return "The system was unable to parse the command line in this file."; +    case NERR_ProfileLoadErr: +      return "An error occurred while loading the profile file."; +    case NERR_ProfileSaveErr: +      return "@W Errors occurred while saving the profile file. The profile was partially saved."; +    case NERR_LogOverflow: +      return "Log file %1 is full."; +    case NERR_LogFileChanged: +      return "This log file has changed between reads."; +    case NERR_LogFileCorrupt: +      return "Log file %1 is corrupt."; +    case NERR_SourceIsDir: +      return "The source path cannot be a directory."; +    case NERR_BadSource: +      return "The source path is illegal."; +    case NERR_BadDest: +      return "The destination path is illegal."; +    case NERR_DifferentServers: +      return "The source and destination paths are on different servers."; +    case NERR_RunSrvPaused: +      return "The Run server you requested is paused."; +    case NERR_ErrCommRunSrv: +      return "An error occurred when communicating with a Run server."; +    case NERR_ErrorExecingGhost: +      return "An error occurred when starting a background process."; +    case NERR_ShareNotFound: +      return "The shared resource you are connected to could not be found."; +    case NERR_InvalidLana: +      return "The LAN adapter number is invalid."; +    case NERR_OpenFiles: +      return "There are open files on the connection."; +    case NERR_ActiveConns: +      return "Active connections still exist."; +    case NERR_BadPasswordCore: +      return "This share name or password is invalid."; +    case NERR_DevInUse: +      return "The device is being accessed by an active process."; +    case NERR_LocalDrive: +      return "The drive letter is in use locally."; +    case NERR_AlertExists: +      return "The specified client is already registered for the specified event."; +    case NERR_TooManyAlerts: +      return "The alert table is full."; +    case NERR_NoSuchAlert: +      return "An invalid or nonexistent alert name was raised."; +    case NERR_BadRecipient: +      return "The alert recipient is invalid."; +    case NERR_AcctLimitExceeded: +      return "A user's session with this server has been deleted."; +    case NERR_InvalidLogSeek: +      return "The log file does not contain the requested record number."; +    case NERR_BadUasConfig: +      return "The user accounts database is not configured correctly."; +    case NERR_InvalidUASOp: +      return "This operation is not permitted when the Netlogon service is running."; +    case NERR_LastAdmin: +      return "This operation is not allowed on the last administrative account."; +    case NERR_DCNotFound: +      return "Could not find domain controller for this domain."; +    case NERR_LogonTrackingError: +      return "Could not set logon information for this user."; +    case NERR_NetlogonNotStarted: +      return "The Netlogon service has not been started."; +    case NERR_CanNotGrowUASFile: +      return "Unable to add to the user accounts database."; +    case NERR_TimeDiffAtDC: +      return "This server's clock is not synchronized with the primary domain controller's clock."; +    case NERR_PasswordMismatch: +      return "A password mismatch has been detected."; +    case NERR_NoSuchServer: +      return "The server identification does not specify a valid server."; +    case NERR_NoSuchSession: +      return "The session identification does not specify a valid session."; +    case NERR_NoSuchConnection: +      return "The connection identification does not specify a valid connection."; +    case NERR_TooManyServers: +      return "There is no space for another entry in the table of available servers."; +    case NERR_TooManySessions: +      return "The server has reached the maximum number of sessions it supports."; +    case NERR_TooManyConnections: +      return "The server has reached the maximum number of connections it supports."; +    case NERR_TooManyFiles: +      return "The server cannot open more files because it has reached its maximum number."; +    case NERR_NoAlternateServers: +      return "There are no alternate servers registered on this server."; +    case NERR_TryDownLevel: +      return "Try down-level (remote admin protocol) version of API instead."; +    case NERR_UPSDriverNotStarted: +      return "The UPS driver could not be accessed by the UPS service."; +    case NERR_UPSInvalidConfig: +      return "The UPS service is not configured correctly."; +    case NERR_UPSInvalidCommPort: +      return "The UPS service could not access the specified Comm Port."; +    case NERR_UPSSignalAsserted: +      return "The UPS indicated a line fail or low battery situation. Service not started."; +    case NERR_UPSShutdownFailed: +      return "The UPS service failed to perform a system shut down."; +    case NERR_BadDosRetCode: +      return "The program below returned an MS-DOS error code:"; +    case NERR_ProgNeedsExtraMem: +      return "The program below needs more memory:"; +    case NERR_BadDosFunction: +      return "The program below called an unsupported MS-DOS function:"; +    case NERR_RemoteBootFailed: +      return "The workstation failed to boot."; +    case NERR_BadFileCheckSum: +      return "The file below is corrupt."; +    case NERR_NoRplBootSystem: +      return "No loader is specified in the boot-block definition file."; +    case NERR_RplLoadrNetBiosErr: +      return "NetBIOS returned an error:      The NCB and SMB are dumped above."; +    case NERR_RplLoadrDiskErr: +      return "A disk I/O error occurred."; +    case NERR_ImageParamErr: +      return "Image parameter substitution failed."; +    case NERR_TooManyImageParams: +      return "Too many image parameters cross disk sector boundaries."; +    case NERR_NonDosFloppyUsed: +      return "The image was not generated from an MS-DOS diskette formatted with /S."; +    case NERR_RplBootRestart: +      return "Remote boot will be restarted later."; +    case NERR_RplSrvrCallFailed: +      return "The call to the Remoteboot server failed."; +    case NERR_CantConnectRplSrvr: +      return "Cannot connect to the Remoteboot server."; +    case NERR_CantOpenImageFile: +      return "Cannot open image file on the Remoteboot server."; +    case NERR_CallingRplSrvr: +      return "Connecting to the Remoteboot server..."; +    case NERR_StartingRplBoot: +      return "Connecting to the Remoteboot server..."; +    case NERR_RplBootServiceTerm: +      return "Remote boot service was stopped; check the error log for the cause of the problem."; +    case NERR_RplBootStartFailed: +      return "Remote boot startup failed; check the error log for the cause of the problem."; +    case NERR_RPL_CONNECTED: +      return "A second connection to a Remoteboot resource is not allowed."; +    case NERR_BrowserConfiguredToNotRun: +      return "The browser service was configured with MaintainServerList=No."; +    case NERR_RplNoAdaptersStarted: +      return "Service failed to start since none of the network adapters started with this service."; +    case NERR_RplBadRegistry: +      return "Service failed to start due to bad startup information in the registry."; +    case NERR_RplBadDatabase: +      return "Service failed to start because its database is absent or corrupt."; +    case NERR_RplRplfilesShare: +      return "Service failed to start because RPLFILES share is absent."; +    case NERR_RplNotRplServer: +      return "Service failed to start because RPLUSER group is absent."; +    case NERR_RplCannotEnum: +      return "Cannot enumerate service records."; +    case NERR_RplWkstaInfoCorrupted: +      return "Workstation record information has been corrupted."; +    case NERR_RplWkstaNotFound: +      return "Workstation record was not found."; +    case NERR_RplWkstaNameUnavailable: +      return "Workstation name is in use by some other workstation."; +    case NERR_RplProfileInfoCorrupted: +      return "Profile record information has been corrupted."; +    case NERR_RplProfileNotFound: +      return "Profile record was not found."; +    case NERR_RplProfileNameUnavailable: +      return "Profile name is in use by some other profile."; +    case NERR_RplProfileNotEmpty: +      return "There are workstations using this profile."; +    case NERR_RplConfigInfoCorrupted: +      return "Configuration record information has been corrupted."; +    case NERR_RplConfigNotFound: +      return "Configuration record was not found."; +    case NERR_RplAdapterInfoCorrupted: +      return "Adapter ID record information has been corrupted."; +    case NERR_RplInternal: +      return "An internal service error has occurred."; +    case NERR_RplVendorInfoCorrupted: +      return "Vendor ID record information has been corrupted."; +    case NERR_RplBootInfoCorrupted: +      return "Boot block record information has been corrupted."; +    case NERR_RplWkstaNeedsUserAcct: +      return "The user account for this workstation record is missing."; +    case NERR_RplNeedsRPLUSERAcct: +      return "The RPLUSER local group could not be found."; +    case NERR_RplBootNotFound: +      return "Boot block record was not found."; +    case NERR_RplIncompatibleProfile: +      return "Chosen profile is incompatible with this workstation."; +    case NERR_RplAdapterNameUnavailable: +      return "Chosen network adapter ID is in use by some other workstation."; +    case NERR_RplConfigNotEmpty: +      return "There are profiles using this configuration."; +    case NERR_RplBootInUse: +      return "There are workstations, profiles, or configurations using this boot block."; +    case NERR_RplBackupDatabase: +      return "Service failed to backup Remoteboot database."; +    case NERR_RplAdapterNotFound: +      return "Adapter record was not found."; +    case NERR_RplVendorNotFound: +      return "Vendor record was not found."; +    case NERR_RplVendorNameUnavailable: +      return "Vendor name is in use by some other vendor record."; +    case NERR_RplBootNameUnavailable: +      return "(boot name, vendor ID) is in use by some other boot block record."; +    case NERR_RplConfigNameUnavailable: +      return "Configuration name is in use by some other configuration."; +    case NERR_DfsInternalCorruption: +      return "The internal database maintained by the Dfs service is corrupt."; +    case NERR_DfsVolumeDataCorrupt: +      return "One of the records in the internal Dfs database is corrupt."; +    case NERR_DfsNoSuchVolume: +      return "There is no DFS name whose entry path matches the input Entry Path."; +    case NERR_DfsVolumeAlreadyExists: +      return "A root or link with the given name already exists."; +    case NERR_DfsAlreadyShared: +      return "The server share specified is already shared in the Dfs."; +    case NERR_DfsNoSuchShare: +      return "The indicated server share does not support the indicated DFS namespace."; +    case NERR_DfsNotALeafVolume: +      return "The operation is not valid on this portion of the namespace."; +    case NERR_DfsLeafVolume: +      return "The operation is not valid on this portion of the namespace."; +    case NERR_DfsVolumeHasMultipleServers: +      return "The operation is ambiguous because the link has multiple servers."; +    case NERR_DfsCantCreateJunctionPoint: +      return "Unable to create a link."; +    case NERR_DfsServerNotDfsAware: +      return "The server is not Dfs Aware."; +    case NERR_DfsBadRenamePath: +      return "The specified rename target path is invalid."; +    case NERR_DfsVolumeIsOffline: +      return "The specified DFS link is offline."; +    case NERR_DfsNoSuchServer: +      return "The specified server is not a server for this link."; +    case NERR_DfsCyclicalName: +      return "A cycle in the Dfs name was detected."; +    case NERR_DfsNotSupportedInServerDfs: +      return "The operation is not supported on a server-based Dfs."; +    case NERR_DfsDuplicateService: +      return "This link is already supported by the specified server-share."; +    case NERR_DfsCantRemoveLastServerShare: +      return "Can't remove the last server-share supporting this root or link."; +    case NERR_DfsVolumeIsInterDfs: +      return "The operation is not supported for an Inter-DFS link."; +    case NERR_DfsInconsistent: +      return "The internal state of the Dfs Service has become inconsistent."; +    case NERR_DfsServerUpgraded: +      return "The Dfs Service has been installed on the specified server."; +    case NERR_DfsDataIsIdentical: +      return "The Dfs data being reconciled is identical."; +    case NERR_DfsCantRemoveDfsRoot: +      return "The DFS root cannot be deleted. Uninstall DFS if required."; +    case NERR_DfsChildOrParentInDfs: +      return "A child or parent directory of the share is already in a Dfs."; +    case NERR_DfsInternalError: +      return "Dfs internal error."; +      /* the following are not defined in mingw */ +#if 0 + +    case NERR_SetupAlreadyJoined: +      return "This machine is already joined to a domain."; +    case NERR_SetupNotJoined: +      return "This machine is not currently joined to a domain."; +    case NERR_SetupDomainController: +      return "This machine is a domain controller and cannot be unjoined from a domain."; +    case NERR_DefaultJoinRequired: +      return "The destination domain controller does not support creating machine accounts in OUs."; +    case NERR_InvalidWorkgroupName: +      return "The specified workgroup name is invalid."; +    case NERR_NameUsesIncompatibleCodePage: +      return "The specified computer name is incompatible with the default language used on the domain controller."; +    case NERR_ComputerAccountNotFound: +      return "The specified computer account could not be found."; +    case NERR_PersonalSku: +      return "This version of Windows cannot be joined to a domain."; +    case NERR_PasswordMustChange: +      return "The password must change at the next logon."; +    case NERR_AccountLockedOut: +      return "The account is locked out."; +    case NERR_PasswordTooLong: +      return "The password is too long."; +    case NERR_PasswordNotComplexEnough: +      return "The password does not meet the complexity policy."; +    case NERR_PasswordFilterError: +      return "The password does not meet the requirements of the password filter DLLs."; +#endif + +    } +  msg = strerror (error_number); +  if (msg == NULL) +    msg = "unknown"; + +  return msg; +#endif //DBUS_WINCE +} + + + + + + + + + +/****************************************************************************** +  +Original CVS version of dbus-sysdeps.c +  +******************************************************************************/ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-Bus implementation) + *  + * Copyright (C) 2002, 2003  Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2005 Novell, Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +int _dbus_mkdir (const char *path, +                 mode_t mode) +{ +  return _mkdir(path); +} + +/** + * Exit the process, returning the given value. + * + * @param code the exit code + */ +void +_dbus_exit (int code) +{ +  _exit (code); +} + +/** + * Creates a socket and connects to a socket at the given host  + * and port. The connection fd is returned, and is set up as + * nonblocking. + * + * @param host the host name to connect to, NULL for loopback + * @param port the prot to connect to + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_tcp_socket (const char     *host, +                          dbus_uint32_t   port, +                          DBusError      *error) +{ +  DBusSocket s; +  int handle; +  struct sockaddr_in addr; +  struct hostent *he; +  struct in_addr *haddr; +  struct in_addr ina; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_win_startup_winsock (); + +  s.fd = socket (AF_INET, SOCK_STREAM, 0); + +  if (DBUS_SOCKET_IS_INVALID (s.fd)) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, +                      _dbus_error_from_errno (errno), +                      "Failed to create socket: %s", +                      _dbus_strerror (errno)); + +      return -1; +    } + +  if (host == NULL) +    { +      host = "localhost"; +      ina.s_addr = htonl (INADDR_LOOPBACK); +      haddr = &ina; +    } + +  he = gethostbyname (host); +  if (he == NULL) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, +                      _dbus_error_from_errno (errno), +                      "Failed to lookup hostname: %s", +                      host); +      DBUS_CLOSE_SOCKET (s.fd); +      return -1; +    } + +  haddr = ((struct in_addr *) (he->h_addr_list)[0]); + +  _DBUS_ZERO (addr); +  memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr)); +  addr.sin_family = AF_INET; +  addr.sin_port = htons (port); + +  if (DBUS_SOCKET_API_RETURNS_ERROR +      (connect (s.fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, +                      _dbus_error_from_errno (errno), +                      "Failed to connect to socket %s:%d %s", +                      host, port, _dbus_strerror (errno)); + +      DBUS_CLOSE_SOCKET (s.fd); +      s.fd = -1; + +      return -1; +    } + +  handle = _dbus_socket_to_handle (&s); + +  if (!_dbus_set_fd_nonblocking (handle, error)) +    { +      _dbus_close_socket (handle, NULL); +      handle = -1; + +      return -1; +    } + +  return handle; +} + +void +_dbus_daemon_init(const char *host, dbus_uint32_t port); +/** + * Creates a socket and binds it to the given port, + * then listens on the socket. The socket is + * set to be nonblocking.  + * + * @param host the interface to listen on, NULL for loopback, empty for any + * @param port the port to listen on, if zero a free port will be used + * @param error return location for errors + * @returns the listening file descriptor or -1 on error + */ + +int +_dbus_listen_tcp_socket (const char     *host, +                         dbus_uint32_t   port, +                         DBusError      *error) +{ +  DBusSocket slisten; +  int handle; +  struct sockaddr_in addr; +  struct hostent *he; +  struct in_addr *haddr; +  int len =  sizeof (struct sockaddr); +  struct in_addr ina; + + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _dbus_win_startup_winsock (); + +  slisten.fd = socket (AF_INET, SOCK_STREAM, 0); + +  if (DBUS_SOCKET_IS_INVALID (slisten.fd)) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to create socket \"%s:%d\": %s", +                      host, port, _dbus_strerror (errno)); +      return -1; +    } +  if (host == NULL) +    { +      host = "localhost"; +      ina.s_addr = htonl (INADDR_LOOPBACK); +      haddr = &ina; +    } +  else if (!host[0]) +    { +      ina.s_addr = htonl (INADDR_ANY); +      haddr = &ina; +    } +  else +    { +      he = gethostbyname (host); +      if (he == NULL) +        { +          DBUS_SOCKET_SET_ERRNO (); +          dbus_set_error (error, +                          _dbus_error_from_errno (errno), +                          "Failed to lookup hostname: %s", +                          host); +          DBUS_CLOSE_SOCKET (slisten.fd); +          return -1; +        } + +      haddr = ((struct in_addr *) (he->h_addr_list)[0]); +    } + +  _DBUS_ZERO (addr); +  memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr)); +  addr.sin_family = AF_INET; +  addr.sin_port = htons (port); + +  if (bind (slisten.fd, (struct sockaddr*) &addr, sizeof (struct sockaddr))) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to bind socket \"%s:%d\": %s", +                      host, port, _dbus_strerror (errno)); +      DBUS_CLOSE_SOCKET (slisten.fd); +      return -1; +    } + +  if (DBUS_SOCKET_API_RETURNS_ERROR (listen (slisten.fd, 30 /* backlog */))) +    { +      DBUS_SOCKET_SET_ERRNO (); +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to listen on socket \"%s:%d\": %s", +                      host, port, _dbus_strerror (errno)); +      DBUS_CLOSE_SOCKET (slisten.fd); +      return -1; +    } + + +  getsockname(slisten.fd, (struct sockaddr*) &addr, &len); + +  _dbus_daemon_init(host, ntohs(addr.sin_port)); + +  handle = _dbus_socket_to_handle (&slisten); + +  if (!_dbus_set_fd_nonblocking (handle, error)) +    { +      _dbus_close_socket (handle, NULL); +      return -1; +    } + +  return handle; +} + +/** + * Accepts a connection on a listening socket. + * Handles EINTR for you. + * + * @param listen_fd the listen file descriptor + * @returns the connection fd of the client, or -1 on error + */ +int +_dbus_accept  (int listen_handle) +{ +  DBusSocket *slisten; +  DBusSocket sclient; +  struct sockaddr addr; +  socklen_t addrlen; + +  _dbus_handle_to_socket(listen_handle, &slisten); + +  addrlen = sizeof (addr); + +  //FIXME:  why do we not try it again on Windows? +#if !defined(DBUS_WIN) && !defined(DBUS_WINCE) +retry: +#endif + +  sclient.fd = accept (slisten->fd, &addr, &addrlen); + +  if (DBUS_SOCKET_IS_INVALID (sclient.fd)) +    { +      DBUS_SOCKET_SET_ERRNO (); +#if !defined(DBUS_WIN) && !defined(DBUS_WINCE) +      if (errno == EINTR) +        goto retry; +#else +      return -1; +#endif +    } + +  return _dbus_socket_to_handle (&sclient); +} + + + +dbus_bool_t +write_credentials_byte (int             server_fd, +                        DBusError      *error) +{ +  /* FIXME: for the session bus credentials shouldn't matter (?), but +   * for the system bus they are presumably essential. A rough outline +   * of a way to implement the credential transfer would be this: +   * +   * client waits to *read* a byte. +   * +   * server creates a named pipe with a random name, sends a byte +   * contining its length, and its name. +   * +   * client reads the name, connects to it (using Win32 API). +   * +   * server waits for connection to the named pipe, then calls +   * ImpersonateNamedPipeClient(), notes its now-current credentials, +   * calls RevertToSelf(), closes its handles to the named pipe, and +   * is done. (Maybe there is some other way to get the SID of a named +   * pipe client without having to use impersonation?) +   * +   * client closes its handles and is done. +   * +   */ + +  return TRUE; +} + +/** + * Reads a single byte which must be nul (an error occurs otherwise), + * and reads unix credentials if available. Fills in pid/uid/gid with + * -1 if no credentials are available. Return value indicates whether + * a byte was read, not whether we got valid credentials. On some + * systems, such as Linux, reading/writing the byte isn't actually + * required, but we do it anyway just to avoid multiple codepaths. + *  + * Fails if no byte is available, so you must select() first. + * + * The point of the byte is that on some systems we have to + * use sendmsg()/recvmsg() to transmit credentials. + * + * @param client_fd the client file descriptor + * @param credentials struct to fill with credentials of client + * @param error location to store error code + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_read_credentials_unix_socket  (int              client_fd, +                                     DBusCredentials *credentials, +                                     DBusError       *error) +{ +  /* FIXME bogus testing credentials */ +  _dbus_credentials_from_current_process (credentials); + +  return TRUE; +} + +/** +* Checks to make sure the given directory is  +* private to the user  +* +* @param dir the name of the directory +* @param error error return +* @returns #FALSE on failure +**/ +dbus_bool_t +_dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) +{ +  const char *directory; +  struct stat sb; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  return TRUE; +} + + +/** + * Gets user info for the given user ID. + * + * @param info user info object to initialize + * @param uid the user ID + * @param error error return + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_user_info_fill_uid (DBusUserInfo *info, +                          dbus_uid_t    uid, +                          DBusError    *error) +{ +  return fill_user_info (info, uid, +                         NULL, error); +} + +/** + * Gets user info for the given username. + * + * @param info user info object to initialize + * @param username the username + * @param error error return + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_user_info_fill (DBusUserInfo     *info, +                      const DBusString *username, +                      DBusError        *error) +{ +  return fill_user_info (info, DBUS_UID_UNSET, +                         username, error); +} + + +dbus_bool_t +fill_user_info (DBusUserInfo       *info, +                dbus_uid_t          uid, +                const DBusString   *username, +                DBusError          *error) +{ +  const char *username_c; + +  /* exactly one of username/uid provided */ +  _dbus_assert (username != NULL || uid != DBUS_UID_UNSET); +  _dbus_assert (username == NULL || uid == DBUS_UID_UNSET); + +  info->uid = DBUS_UID_UNSET; +  info->primary_gid = DBUS_GID_UNSET; +  info->group_ids = NULL; +  info->n_group_ids = 0; +  info->username = NULL; +  info->homedir = NULL; + +  if (username != NULL) +    username_c = _dbus_string_get_const_data (username); +  else +    username_c = NULL; + +  if (uid != DBUS_UID_UNSET) +    { +      if (!fill_win_user_info_from_uid (uid, info, error)) +        { +          _dbus_verbose("%s after fill_win_user_info_from_uid\n",__FUNCTION__); +          return FALSE; +        } +    } +  else +    { +      wchar_t *wname = _dbus_win_utf8_to_utf16 (username_c, error); + +      if (!wname) +        return FALSE; + +      if (!fill_win_user_info_from_name (wname, info, error)) +        { +          dbus_free (wname); +          return FALSE; +        } +      dbus_free (wname); +    } + +  return TRUE; +} + + +/** + * Appends the given filename to the given directory. + * + * @todo it might be cute to collapse multiple '/' such as "foo//" + * concat "//bar" + * + * @param dir the directory name + * @param next_component the filename + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_concat_dir_and_file (DBusString       *dir, +                           const DBusString *next_component) +{ +  dbus_bool_t dir_ends_in_slash; +  dbus_bool_t file_starts_with_slash; + +  if (_dbus_string_get_length (dir) == 0 || +      _dbus_string_get_length (next_component) == 0) +    return TRUE; + +  dir_ends_in_slash = +    ('/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1) || +     '\\' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1)); + +  file_starts_with_slash = +    ('/' == _dbus_string_get_byte (next_component, 0) || +     '\\' == _dbus_string_get_byte (next_component, 0)); + +  if (dir_ends_in_slash && file_starts_with_slash) +    { +      _dbus_string_shorten (dir, 1); +    } +  else if (!(dir_ends_in_slash || file_starts_with_slash)) +    { +      if (!_dbus_string_append_byte (dir, '\\')) +        return FALSE; +    } + +  return _dbus_string_copy (next_component, 0, dir, +                            _dbus_string_get_length (dir)); +} + + + + +/** + * Gets our process ID + * @returns process ID + */ +unsigned long +_dbus_getpid (void) +{ +  return GetCurrentProcessId (); +} + +/** nanoseconds in a second */ +#define NANOSECONDS_PER_SECOND       1000000000 +/** microseconds in a second */ +#define MICROSECONDS_PER_SECOND      1000000 +/** milliseconds in a second */ +#define MILLISECONDS_PER_SECOND      1000 +/** nanoseconds in a millisecond */ +#define NANOSECONDS_PER_MILLISECOND  1000000 +/** microseconds in a millisecond */ +#define MICROSECONDS_PER_MILLISECOND 1000 + +/** + * Sleeps the given number of milliseconds. + * @param milliseconds number of milliseconds + */ +void +_dbus_sleep_milliseconds (int milliseconds) +{ +  Sleep (milliseconds); +} + + +/** + * Get current time, as in gettimeofday(). + * + * @param tv_sec return location for number of seconds + * @param tv_usec return location for number of microseconds + */ +void +_dbus_get_current_time (long *tv_sec, +                        long *tv_usec) +{ +  FILETIME ft; +  dbus_uint64_t *time64 = (dbus_uint64_t *) &ft; + +  GetSystemTimeAsFileTime (&ft); + +  /* Convert from 100s of nanoseconds since 1601-01-01 +  * to Unix epoch. Yes, this is Y2038 unsafe. +  */ +  *time64 -= DBUS_INT64_CONSTANT (116444736000000000); +  *time64 /= 10; + +  if (tv_sec) +    *tv_sec = *time64 / 1000000; + +  if (tv_usec) +    *tv_usec = *time64 % 1000000; +} + + +/** + * signal (SIGPIPE, SIG_IGN); + */ +void +_dbus_disable_sigpipe (void) +{ +    _dbus_verbose("FIXME: implement _dbus_disable_sigpipe (void)\n"); +} + +/** + * Gets the credentials of the current process. + * + * @param credentials credentials to fill in. + */ +void +_dbus_credentials_from_current_process (DBusCredentials *credentials) +{ +  credentials->pid = _dbus_getpid (); +  credentials->uid = _dbus_getuid (); +  credentials->gid = _dbus_getgid (); +} + +/** + * Appends the contents of the given file to the string, + * returning error code. At the moment, won't open a file + * more than a megabyte in size. + * + * @param str the string to append to + * @param filename filename to load + * @param error place to set an error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_file_get_contents (DBusString       *str, +                         const DBusString *filename, +                         DBusError        *error) +{ +  DBusFile file; +  struct stat sb; +  int orig_len; +  int total; +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  /* O_BINARY useful on Cygwin and Win32 */ +  if (!_dbus_open_file (&file, filename_c, O_RDONLY | O_BINARY, -1)) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to open \"%s\": %s", +                      filename_c, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  if (!_dbus_fstat (&file, &sb)) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Failed to stat \"%s\": %s", +                      filename_c, +                      _dbus_strerror (errno)); + +      _dbus_verbose ("fstat() failed: %s", +                     _dbus_strerror (errno)); + +      _dbus_close_file (&file, NULL); + +      return FALSE; +    } + +  if (sb.st_size > _DBUS_ONE_MEGABYTE) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "File size %lu of \"%s\" is too large.", +                      (unsigned long) sb.st_size, filename_c); +      _dbus_close_file (&file, NULL); +      return FALSE; +    } + +  total = 0; +  orig_len = _dbus_string_get_length (str); +  if (sb.st_size > 0 && S_ISREG (sb.st_mode)) +    { +      int bytes_read; + +      while (total < (int) sb.st_size) +        { +          bytes_read = _dbus_read_file (&file, str, +                                        sb.st_size - total); +          if (bytes_read <= 0) +            { +              dbus_set_error (error, _dbus_error_from_errno (errno), +                              "Error reading \"%s\": %s", +                              filename_c, +                              _dbus_strerror (errno)); + +              _dbus_verbose ("read() failed: %s", +                             _dbus_strerror (errno)); + +              _dbus_close_file (&file, NULL); +              _dbus_string_set_length (str, orig_len); +              return FALSE; +            } +          else +            total += bytes_read; +        } + +      _dbus_close_file (&file, NULL); +      return TRUE; +    } +  else if (sb.st_size != 0) +    { +      _dbus_verbose ("Can only open regular files at the moment.\n"); +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "\"%s\" is not a regular file", +                      filename_c); +      _dbus_close_file (&file, NULL); +      return FALSE; +    } +  else +    { +      _dbus_close_file (&file, NULL); +      return TRUE; +    } +} + +/** + * Writes a string out to a file. If the file exists, + * it will be atomically overwritten by the new data. + * + * @param str the string to write out + * @param filename the file to save string to + * @param error error to be filled in on failure + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_string_save_to_file (const DBusString *str, +                           const DBusString *filename, +                           DBusError        *error) +{ +  DBusFile file; +  int bytes_to_write; +  const char *filename_c; +  DBusString tmp_filename; +  const char *tmp_filename_c; +  int total; +  dbus_bool_t need_unlink; +  dbus_bool_t retval; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  retval = FALSE; +  need_unlink = FALSE; + +  if (!_dbus_string_init (&tmp_filename)) +    { +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      return FALSE; +    } + +  if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) +    { +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      _dbus_string_free (&tmp_filename); +      return FALSE; +    } + +  if (!_dbus_string_append (&tmp_filename, ".")) +    { +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      _dbus_string_free (&tmp_filename); +      return FALSE; +    } + +#define N_TMP_FILENAME_RANDOM_BYTES 8 +  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES)) +    { +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      _dbus_string_free (&tmp_filename); +      return FALSE; +    } + +  filename_c = _dbus_string_get_const_data (filename); +  tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); + +  if (!_dbus_open_file (&file, tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, +                        0600)) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Could not create %s: %s", tmp_filename_c, +                      _dbus_strerror (errno)); +      goto out; +    } + +  need_unlink = TRUE; + +  total = 0; +  bytes_to_write = _dbus_string_get_length (str); + +  while (total < bytes_to_write) +    { +      int bytes_written; + +      bytes_written = _dbus_write_file (&file, str, total, +                                        bytes_to_write - total); + +      if (bytes_written <= 0) +        { +          dbus_set_error (error, _dbus_error_from_errno (errno), +                          "Could not write to %s: %s", tmp_filename_c, +                          _dbus_strerror (errno)); + +          goto out; +        } + +      total += bytes_written; +    } + +  if (!_dbus_close_file (&file, NULL)) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Could not close file %s: %s", +                      tmp_filename_c, _dbus_strerror (errno)); + +      goto out; +    } + + +  if ((unlink (filename_c) == -1 && errno != ENOENT) || +       rename (tmp_filename_c, filename_c) < 0) +    { +      dbus_set_error (error, _dbus_error_from_errno (errno), +                      "Could not rename %s to %s: %s", +                      tmp_filename_c, filename_c, +                      _dbus_strerror (errno)); + +      goto out; +    } + +  need_unlink = FALSE; + +  retval = TRUE; + +out: +  /* close first, then unlink, to prevent ".nfs34234235" garbage +   * files +   */ + +  if (_dbus_is_valid_file(&file)) +    _dbus_close_file (&file, NULL); + +  if (need_unlink && unlink (tmp_filename_c) < 0) +    _dbus_verbose ("Failed to unlink temp file %s: %s\n", +                   tmp_filename_c, _dbus_strerror (errno)); + +  _dbus_string_free (&tmp_filename); + +  if (!retval) +    _DBUS_ASSERT_ERROR_IS_SET (error); + +  return retval; +} + + +/** Creates the given file, failing if the file already exists. + * + * @param filename the filename + * @param error error location + * @returns #TRUE if we created the file and it didn't exist + */ +dbus_bool_t +_dbus_create_file_exclusively (const DBusString *filename, +                               DBusError        *error) +{ +  DBusFile file; +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  if (!_dbus_open_file (&file, filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, +                        0600)) +    { +      dbus_set_error (error, +                      DBUS_ERROR_FAILED, +                      "Could not create file %s: %s\n", +                      filename_c, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  if (!_dbus_close_file (&file, NULL)) +    { +      dbus_set_error (error, +                      DBUS_ERROR_FAILED, +                      "Could not close file %s: %s\n", +                      filename_c, +                      _dbus_strerror (errno)); +      return FALSE; +    } + +  return TRUE; +} + + +/** + * Creates a directory; succeeds if the directory + * is created or already existed. + * + * @param filename directory filename + * @param error initialized error object + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_create_directory (const DBusString *filename, +                        DBusError        *error) +{ +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  if (_dbus_mkdir (filename_c, 0700) < 0) +    { +      if (errno == EEXIST) +        return TRUE; + +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Failed to create directory %s: %s\n", +                      filename_c, _dbus_strerror (errno)); +      return FALSE; +    } +  else +    return TRUE; +} + + +static void +pseudorandom_generate_random_bytes_buffer (char *buffer, +    int   n_bytes) +{ +  long tv_usec; +  int i; + +  /* fall back to pseudorandom */ +  _dbus_verbose ("Falling back to pseudorandom for %d bytes\n", +                 n_bytes); + +  _dbus_get_current_time (NULL, &tv_usec); +  srand (tv_usec); + +  i = 0; +  while (i < n_bytes) +    { +      double r; +      unsigned int b; + +      r = rand (); +      b = (r / (double) RAND_MAX) * 255.0; + +      buffer[i] = b; + +      ++i; +    } +} + +static dbus_bool_t +pseudorandom_generate_random_bytes (DBusString *str, +                                    int         n_bytes) +{ +  int old_len; +  char *p; + +  old_len = _dbus_string_get_length (str); + +  if (!_dbus_string_lengthen (str, n_bytes)) +    return FALSE; + +  p = _dbus_string_get_data_len (str, old_len, n_bytes); + +  pseudorandom_generate_random_bytes_buffer (p, n_bytes); + +  return TRUE; +} + +/** + * Gets the temporary files directory by inspecting the environment variables  + * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned + * + * @returns location of temp directory + */ +const char* +_dbus_get_tmpdir(void) +{ +  static const char* tmpdir = NULL; + +  if (tmpdir == NULL) +    { +      if (tmpdir == NULL) +        tmpdir = getenv("TMP"); +      if (tmpdir == NULL) +        tmpdir = getenv("TEMP"); +      if (tmpdir == NULL) +        tmpdir = getenv("TMPDIR"); +      if (tmpdir == NULL) +          tmpdir = "C:\\Temp"; +    } + +  _dbus_assert(tmpdir != NULL); + +  return tmpdir; +} + + +/** + * Deletes the given file. + * + * @param filename the filename + * @param error error location + *  + * @returns #TRUE if unlink() succeeded + */ +dbus_bool_t +_dbus_delete_file (const DBusString *filename, +                   DBusError        *error) +{ +  const char *filename_c; + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  filename_c = _dbus_string_get_const_data (filename); + +  if (unlink (filename_c) < 0) +    { +      dbus_set_error (error, DBUS_ERROR_FAILED, +                      "Failed to delete file %s: %s\n", +                      filename_c, _dbus_strerror (errno)); +      return FALSE; +    } +  else +    return TRUE; +} + +/** + * Generates the given number of random bytes, + * using the best mechanism we can come up with. + * + * @param str the string + * @param n_bytes the number of random bytes to append to string + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +_dbus_generate_random_bytes (DBusString *str, +                             int         n_bytes) +{ +  return pseudorandom_generate_random_bytes (str, n_bytes); +} + +#if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_BUILD_TESTS) + +#ifdef _MSC_VER +# ifdef BACKTRACES +#  undef BACKTRACES +# endif +#else +# define BACKTRACES +#endif + +#ifdef BACKTRACES +/* + * Backtrace Generator + * + * Copyright 2004 Eric Poech + * Copyright 2004 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <winver.h> +#include <imagehlp.h> +#include <stdio.h> + +#define DPRINTF _dbus_warn + +#ifdef _MSC_VER +#define BOOL int + +#define __i386__ +#endif + +//#define MAKE_FUNCPTR(f) static typeof(f) * p##f + +//MAKE_FUNCPTR(StackWalk); +//MAKE_FUNCPTR(SymGetModuleBase); +//MAKE_FUNCPTR(SymFunctionTableAccess); +//MAKE_FUNCPTR(SymInitialize); +//MAKE_FUNCPTR(SymGetSymFromAddr); +//MAKE_FUNCPTR(SymGetModuleInfo); +static BOOL (WINAPI *pStackWalk)( +  DWORD MachineType, +  HANDLE hProcess, +  HANDLE hThread, +  LPSTACKFRAME StackFrame, +  PVOID ContextRecord, +  PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, +  PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, +  PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, +  PTRANSLATE_ADDRESS_ROUTINE TranslateAddress +); +static DWORD (WINAPI *pSymGetModuleBase)( +  HANDLE hProcess, +  DWORD dwAddr +); +static PVOID  (WINAPI *pSymFunctionTableAccess)( +  HANDLE hProcess, +  DWORD AddrBase +); +static BOOL  (WINAPI *pSymInitialize)( +  HANDLE hProcess, +  PSTR UserSearchPath, +  BOOL fInvadeProcess +); +static BOOL  (WINAPI *pSymGetSymFromAddr)( +  HANDLE hProcess, +  DWORD Address, +  PDWORD Displacement, +  PIMAGEHLP_SYMBOL Symbol +); +static BOOL  (WINAPI *pSymGetModuleInfo)( +  HANDLE hProcess, +  DWORD dwAddr, +  PIMAGEHLP_MODULE ModuleInfo +); +static DWORD  (WINAPI *pSymSetOptions)( +  DWORD SymOptions +); + + +static BOOL init_backtrace() +{ +    HMODULE hmodDbgHelp = LoadLibraryA("dbghelp"); +/* +    #define GETFUNC(x) \ +    p##x = (typeof(x)*)GetProcAddress(hmodDbgHelp, #x); \ +    if (!p##x) \ +    { \ +        return FALSE; \ +    } +    */ + + +//    GETFUNC(StackWalk); +//    GETFUNC(SymGetModuleBase); +//    GETFUNC(SymFunctionTableAccess); +//    GETFUNC(SymInitialize); +//    GETFUNC(SymGetSymFromAddr); +//    GETFUNC(SymGetModuleInfo); + +#define FUNC(x) #x + +      pStackWalk = (BOOL  (WINAPI *)( +DWORD MachineType, +HANDLE hProcess, +HANDLE hThread, +LPSTACKFRAME StackFrame, +PVOID ContextRecord, +PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, +PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, +PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, +PTRANSLATE_ADDRESS_ROUTINE TranslateAddress +))GetProcAddress (hmodDbgHelp, FUNC(StackWalk)); +    pSymGetModuleBase=(DWORD  (WINAPI *)( +  HANDLE hProcess, +  DWORD dwAddr +))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase)); +    pSymFunctionTableAccess=(PVOID  (WINAPI *)( +  HANDLE hProcess, +  DWORD AddrBase +))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess)); +    pSymInitialize = (BOOL  (WINAPI *)( +  HANDLE hProcess, +  PSTR UserSearchPath, +  BOOL fInvadeProcess +))GetProcAddress (hmodDbgHelp, FUNC(SymInitialize)); +    pSymGetSymFromAddr = (BOOL  (WINAPI *)( +  HANDLE hProcess, +  DWORD Address, +  PDWORD Displacement, +  PIMAGEHLP_SYMBOL Symbol +))GetProcAddress (hmodDbgHelp, FUNC(SymGetSymFromAddr)); +    pSymGetModuleInfo = (BOOL  (WINAPI *)( +  HANDLE hProcess, +  DWORD dwAddr, +  PIMAGEHLP_MODULE ModuleInfo +))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleInfo)); +pSymSetOptions = (DWORD  (WINAPI *)( +DWORD SymOptions +))GetProcAddress (hmodDbgHelp, FUNC(SymSetOptions)); + + +    pSymSetOptions(SYMOPT_UNDNAME); + +    pSymInitialize(GetCurrentProcess(), NULL, TRUE); + +    return TRUE; +} + +static void dump_backtrace_for_thread(HANDLE hThread) +{ +    STACKFRAME sf; +    CONTEXT context; +    DWORD dwImageType; + +    if (!pStackWalk) +        if (!init_backtrace()) +            return; + +    /* can't use this function for current thread as GetThreadContext +     * doesn't support getting context from current thread */ +    if (hThread == GetCurrentThread()) +        return; + +    DPRINTF("Backtrace:\n"); + +    memset(&context, 0, sizeof(context)); +    context.ContextFlags = CONTEXT_FULL; + +    SuspendThread(hThread); + +    if (!GetThreadContext(hThread, &context)) +    { +        DPRINTF("Couldn't get thread context (error %ld)\n", GetLastError()); +        ResumeThread(hThread); +        return; +    } + +    memset(&sf, 0, sizeof(sf)); + +#ifdef __i386__ +    sf.AddrFrame.Offset = context.Ebp; +    sf.AddrFrame.Mode = AddrModeFlat; +    sf.AddrPC.Offset = context.Eip; +    sf.AddrPC.Mode = AddrModeFlat; +    dwImageType = IMAGE_FILE_MACHINE_I386; +#else +# error You need to fill in the STACKFRAME structure for your architecture +#endif + +    while (pStackWalk(dwImageType, GetCurrentProcess(), +                     hThread, &sf, &context, NULL, pSymFunctionTableAccess, +                     pSymGetModuleBase, NULL)) +    { +        BYTE buffer[256]; +        IMAGEHLP_SYMBOL * pSymbol = (IMAGEHLP_SYMBOL *)buffer; +        DWORD dwDisplacement; + +        pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); +        pSymbol->MaxNameLength = sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL) + 1; + +        if (!pSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, +                                &dwDisplacement, pSymbol)) +        { +            IMAGEHLP_MODULE ModuleInfo; +            ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); + +            if (!pSymGetModuleInfo(GetCurrentProcess(), sf.AddrPC.Offset, +                                   &ModuleInfo)) +                DPRINTF("1\t%p\n", (void*)sf.AddrPC.Offset); +            else +                DPRINTF("2\t%s+0x%lx\n", ModuleInfo.ImageName, +                    sf.AddrPC.Offset - ModuleInfo.BaseOfImage); +        } +        else if (dwDisplacement) +            DPRINTF("3\t%s+0x%lx\n", pSymbol->Name, dwDisplacement); +        else +            DPRINTF("4\t%s\n", pSymbol->Name); +    } + +    ResumeThread(hThread); +} + +static DWORD WINAPI dump_thread_proc(LPVOID lpParameter) +{ +    dump_backtrace_for_thread((HANDLE)lpParameter); +    return 0; +} + +/* cannot get valid context from current thread, so we have to execute + * backtrace from another thread */ +static void dump_backtrace() +{ +    HANDLE hCurrentThread; +    HANDLE hThread; +    DWORD dwThreadId; +    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), +        GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS); +    hThread = CreateThread(NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread, +        0, &dwThreadId); +    WaitForSingleObject(hThread, INFINITE); +    CloseHandle(hThread); +    CloseHandle(hCurrentThread); +} + +void _dbus_print_backtrace(void) +{ +  init_backtrace(); +  dump_backtrace(); +} +#else +void _dbus_print_backtrace(void) +{ +  _dbus_verbose ("  D-Bus not compiled with backtrace support\n"); +} +#endif + +/** + * Sends a single nul byte with our UNIX credentials as ancillary + * data.  Returns #TRUE if the data was successfully written.  On + * systems that don't support sending credentials, just writes a byte, + * doesn't send any credentials.  On some systems, such as Linux, + * reading/writing the byte isn't actually required, but we do it + * anyway just to avoid multiple codepaths. + * + * Fails if no byte can be written, so you must select() first. + * + * The point of the byte is that on some systems we have to + * use sendmsg()/recvmsg() to transmit credentials. + * + * @param server_fd file descriptor for connection to server + * @param error return location for error code + * @returns #TRUE if the byte was sent + */ +dbus_bool_t +_dbus_send_credentials_unix_socket  (int              server_fd, +                                     DBusError       *error) +{ +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  if (write_credentials_byte (server_fd, error)) +    return TRUE; +  else +    return FALSE; +} + +static dbus_uint32_t fromAscii(char ascii) +{ +    if(ascii >= '0' && ascii <= '9') +        return ascii - '0'; +    if(ascii >= 'A' && ascii <= 'F') +        return ascii - 'A' + 10; +    if(ascii >= 'a' && ascii <= 'f') +        return ascii - 'a' + 10; +    return 0;     +} + +dbus_bool_t _dbus_read_local_machine_uuid   (DBusGUID         *machine_id, +                                             dbus_bool_t       create_if_not_found, +                                             DBusError        *error) +{ +#ifdef DBUS_WINCE +	return TRUE; +  // TODO +#else +    HW_PROFILE_INFOA info; +    char *lpc = &info.szHwProfileGuid[0]; +    dbus_uint32_t u; + +    //  the hw-profile guid lives long enough +    if(!GetCurrentHwProfileA(&info)) +      { +        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); // FIXME +        return FALSE;   +      } + +    // Form: {12340001-4980-1920-6788-123456789012} +    lpc++; +    // 12340001 +    u = ((fromAscii(lpc[0]) <<  0) | +         (fromAscii(lpc[1]) <<  4) | +         (fromAscii(lpc[2]) <<  8) | +         (fromAscii(lpc[3]) << 12) | +         (fromAscii(lpc[4]) << 16) | +         (fromAscii(lpc[5]) << 20) | +         (fromAscii(lpc[6]) << 24) | +         (fromAscii(lpc[7]) << 28)); +    machine_id->as_uint32s[0] = u; + +    lpc += 9; +    // 4980-1920 +    u = ((fromAscii(lpc[0]) <<  0) | +         (fromAscii(lpc[1]) <<  4) | +         (fromAscii(lpc[2]) <<  8) | +         (fromAscii(lpc[3]) << 12) | +         (fromAscii(lpc[5]) << 16) | +         (fromAscii(lpc[6]) << 20) | +         (fromAscii(lpc[7]) << 24) | +         (fromAscii(lpc[8]) << 28)); +    machine_id->as_uint32s[1] = u; +     +    lpc += 10; +    // 6788-1234 +    u = ((fromAscii(lpc[0]) <<  0) | +         (fromAscii(lpc[1]) <<  4) | +         (fromAscii(lpc[2]) <<  8) | +         (fromAscii(lpc[3]) << 12) | +         (fromAscii(lpc[5]) << 16) | +         (fromAscii(lpc[6]) << 20) | +         (fromAscii(lpc[7]) << 24) | +         (fromAscii(lpc[8]) << 28)); +    machine_id->as_uint32s[2] = u; +     +    lpc += 9; +    // 56789012 +    u = ((fromAscii(lpc[0]) <<  0) | +         (fromAscii(lpc[1]) <<  4) | +         (fromAscii(lpc[2]) <<  8) | +         (fromAscii(lpc[3]) << 12) | +         (fromAscii(lpc[4]) << 16) | +         (fromAscii(lpc[5]) << 20) | +         (fromAscii(lpc[6]) << 24) | +         (fromAscii(lpc[7]) << 28)); +    machine_id->as_uint32s[3] = u; +#endif +    return TRUE; +} + +static +HANDLE _dbus_global_lock (const char *mutexname) +{ +  HANDLE mutex; +  DWORD gotMutex; + +  mutex = CreateMutex( NULL, FALSE, mutexname ); +  if( !mutex ) +    { +      return FALSE; +    } + +   gotMutex = WaitForSingleObject( mutex, INFINITE ); +   switch( gotMutex ) +     { +       case WAIT_ABANDONED: +               ReleaseMutex (mutex); +               CloseHandle (mutex); +               return 0; +       case WAIT_FAILED: +       case WAIT_TIMEOUT: +               return 0; +     } + +   return mutex; +} + +static +void _dbus_global_unlock (HANDLE mutex) +{ +  ReleaseMutex (mutex); +  CloseHandle (mutex);  +} + +// for proper cleanup in dbus-daemon +static HANDLE hDBusDaemonMutex = NULL; +static HANDLE hDBusSharedMem = NULL; +// sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs +static const char *cUniqueDBusInitMutex = "UniqueDBusInitMutex"; +// sync _dbus_get_autolaunch_address +static const char *cDBusAutolaunchMutex = "DBusAutolaunchMutex"; +// mutex to determine if dbus-daemon is already started (per user) +static const char *cDBusDaemonMutex = "DBusDaemonMutex"; +// named shm for dbus adress info (per user) +static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo"; + +void +_dbus_daemon_init(const char *host, dbus_uint32_t port) +{ +  HANDLE lock; +  const char *adr = NULL; +  char szUserName[64]; +  DWORD dwUserNameSize = sizeof(szUserName); +  char szDBusDaemonMutex[128]; +  char szDBusDaemonAddressInfo[128]; +  char szAddress[128]; + +  _dbus_assert(host); +  _dbus_assert(port); + +  _snprintf(szAddress, sizeof(szAddress) - 1, "tcp:host=%s,port=%d", host, port); + +  _dbus_assert( GetUserName(szUserName, &dwUserNameSize) != 0); +  _snprintf(szDBusDaemonMutex, sizeof(szDBusDaemonMutex) - 1, "%s:%s", +            cDBusDaemonMutex, szUserName); +  _snprintf(szDBusDaemonAddressInfo, sizeof(szDBusDaemonAddressInfo) - 1, "%s:%s", +            cDBusDaemonAddressInfo, szUserName); + +  // before _dbus_global_lock to keep correct lock/release order +  hDBusDaemonMutex = CreateMutex( NULL, FALSE, szDBusDaemonMutex ); + +  _dbus_assert(WaitForSingleObject( hDBusDaemonMutex, 1000 ) == WAIT_OBJECT_0); + +  // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs +  lock = _dbus_global_lock( cUniqueDBusInitMutex ); + +  // create shm +  hDBusSharedMem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, +                                      0, strlen( szAddress ) + 1, szDBusDaemonAddressInfo ); +  _dbus_assert( hDBusSharedMem ); + +  adr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 ); + +  _dbus_assert( adr ); + +  strcpy(adr, szAddress); + +  // cleanup +  UnmapViewOfFile( adr ); + +  _dbus_global_unlock( lock ); +} + +void +_dbus_daemon_release() +{ +  HANDLE lock; + +  // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs +  lock = _dbus_global_lock( cUniqueDBusInitMutex ); + +  CloseHandle( hDBusSharedMem ); + +  hDBusSharedMem = NULL; + +  ReleaseMutex( hDBusDaemonMutex ); + +  CloseHandle( hDBusDaemonMutex ); + +  hDBusDaemonMutex = NULL; + +  _dbus_global_unlock( lock ); +} + +static dbus_bool_t +_dbus_get_autolaunch_shm(DBusString *adress) +{ +  HANDLE sharedMem; +  const char *adr; +  char szUserName[64]; +  DWORD dwUserNameSize = sizeof(szUserName); +  char szDBusDaemonAddressInfo[128]; + +  if( !GetUserName(szUserName, &dwUserNameSize) ) +      return FALSE; +  _snprintf(szDBusDaemonAddressInfo, sizeof(szDBusDaemonAddressInfo) - 1, "%s:%s", +            cDBusDaemonAddressInfo, szUserName); + +  // read shm +  do { +      // we know that dbus-daemon is available, so we wait until shm is available +      sharedMem = OpenFileMapping( FILE_MAP_READ, FALSE, szDBusDaemonAddressInfo ); +      if( sharedMem == 0 ) +          Sleep( 100 ); +  } while( sharedMem == 0 ); + +  if( sharedMem == 0 ) +      return FALSE; + +  adr = MapViewOfFile( sharedMem, FILE_MAP_READ, 0, 0, 0 ); + +  if( adr == 0 ) +      return FALSE; + +  _dbus_string_init( adress ); + +  _dbus_string_append( adress, adr );  + +  // cleanup +  UnmapViewOfFile( adr ); + +  CloseHandle( sharedMem ); + +  return TRUE; +} + +static dbus_bool_t +_dbus_daemon_already_runs (DBusString *adress) +{ +  HANDLE lock; +  HANDLE daemon; +  dbus_bool_t bRet = TRUE; +  char szUserName[64]; +  DWORD dwUserNameSize = sizeof(szUserName); +  char szDBusDaemonMutex[128]; + +  // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs +  lock = _dbus_global_lock( cUniqueDBusInitMutex ); + +  if( !GetUserName(szUserName, &dwUserNameSize) ) +      return FALSE; +  _snprintf(szDBusDaemonMutex, sizeof(szDBusDaemonMutex) - 1, "%s:%s", +            cDBusDaemonMutex, szUserName); + +  // do checks +  daemon = CreateMutex( NULL, FALSE, szDBusDaemonMutex ); +  if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT) +    { +      ReleaseMutex (daemon); +      CloseHandle (daemon); + +      _dbus_global_unlock( lock ); +      return FALSE; +    } + +  // read shm +  bRet = _dbus_get_autolaunch_shm( adress ); + +  // cleanup +  CloseHandle ( daemon ); + +  _dbus_global_unlock( lock ); + +  return bRet; +} + +dbus_bool_t +_dbus_get_autolaunch_address (DBusString *address,  +                              DBusError *error) +{ +  HANDLE mutex; +  STARTUPINFOA si; +  PROCESS_INFORMATION pi; +  dbus_bool_t retval = FALSE; +  LPSTR lpFile; +  char dbus_exe_path[MAX_PATH]; +  char dbus_args[MAX_PATH * 2]; + +  mutex = _dbus_global_lock ( cDBusAutolaunchMutex ); + +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  if (_dbus_daemon_already_runs(address)) +    { +        printf("dbus daemon already exists\n"); +        retval = TRUE; +        goto out; +    } + +  if (!SearchPathA(NULL, "dbus-daemon.exe", NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile)) +    { +      printf ("could not find dbus-daemon executable\n"); +      goto out; +    } + +  // Create process +  ZeroMemory( &si, sizeof(si) ); +  si.cb = sizeof(si); +  ZeroMemory( &pi, sizeof(pi) ); + +  _snprintf(dbus_args, sizeof(dbus_args) - 1, "\"%s\" %s", dbus_exe_path,  " --session"); + +//  argv[i] = "--config-file=bus\\session.conf"; +  printf("create process \"%s\" %s\n", dbus_exe_path, dbus_args); +  if(CreateProcessA(dbus_exe_path, dbus_args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) +    { +      retval = TRUE; + +      // Wait until started (see _dbus_get_autolaunch_shm()) +      WaitForInputIdle(pi.hProcess, INFINITE); + +      retval = _dbus_get_autolaunch_shm( address ); +    } else { +      retval = FALSE; +    } +   +out: +  if (retval) +    _DBUS_ASSERT_ERROR_IS_CLEAR (error); +  else +    _DBUS_ASSERT_ERROR_IS_SET (error); +   +  _dbus_global_unlock (mutex); + +  return retval; + } + + +/** Makes the file readable by every user in the system. + * + * @param filename the filename + * @param error error location + * @returns #TRUE if the file's permissions could be changed. + */ +dbus_bool_t +_dbus_make_file_world_readable(const DBusString *filename, +                               DBusError *error) +{ +  // TODO +  return TRUE; +} + + +#define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services" + +// @TODO: this function is duplicated from dbus-sysdeps-unix.c +//        and differs only in the path separator, may be we should  +//        use a dbus path separator variable + +#define _dbus_path_seperator ";" + +static dbus_bool_t +split_paths_and_append (DBusString *dirs,  +                        const char *suffix,  +                        DBusList **dir_list) +{ +   int start; +   int i; +   int len; +   char *cpath; +   const DBusString file_suffix; + +   start = 0; +   i = 0; + +   _dbus_string_init_const (&file_suffix, suffix); + +   len = _dbus_string_get_length (dirs); + +   while (_dbus_string_find (dirs, start, _dbus_path_seperator, &i)) +     { +       DBusString path; + +       if (!_dbus_string_init (&path)) +          goto oom; + +       if (!_dbus_string_copy_len (dirs, +                                   start, +                                   i - start, +                                   &path, +                                   0)) +          { +            _dbus_string_free (&path); +            goto oom; +          } + +        _dbus_string_chop_white (&path); + +        /* check for an empty path */ +        if (_dbus_string_get_length (&path) == 0) +          goto next; + +        if (!_dbus_concat_dir_and_file (&path, +                                        &file_suffix)) +          { +            _dbus_string_free (&path); +            goto oom; +          } + +        if (!_dbus_string_copy_data(&path, &cpath)) +          { +            _dbus_string_free (&path); +            goto oom; +          } + +        if (!_dbus_list_append (dir_list, cpath)) +          { +            _dbus_string_free (&path);               +            dbus_free (cpath); +            goto oom; +          } + +       next: +        _dbus_string_free (&path); +        start = i + 1; +    }  +       +  if (start != len) +    {  +      DBusString path; + +      if (!_dbus_string_init (&path)) +        goto oom; + +      if (!_dbus_string_copy_len (dirs, +                                  start, +                                  len - start, +                                  &path, +                                  0)) +        { +          _dbus_string_free (&path); +          goto oom; +        } + +      if (!_dbus_concat_dir_and_file (&path, +                                      &file_suffix)) +        { +          _dbus_string_free (&path); +          goto oom; +        } + +      if (!_dbus_string_copy_data(&path, &cpath)) +        { +          _dbus_string_free (&path); +          goto oom; +        } + +      if (!_dbus_list_append (dir_list, cpath)) +        { +          _dbus_string_free (&path);               +          dbus_free (cpath); +          goto oom; +        } + +      _dbus_string_free (&path);  +    } + +  return TRUE; + + oom: +  _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL);  +  _dbus_list_clear (dir_list); +  return FALSE; +} + +/** + * Returns the standard directories for a session bus to look for service  + * activation files  + * + * On Windows this should be data directories: + * + * %CommonProgramFiles%/dbus + * + * and + * + * DBUS_DATADIR + * + * @param dirs the directory list we are returning + * @returns #FALSE on OOM  + */ + +dbus_bool_t  +_dbus_get_standard_session_servicedirs (DBusList **dirs) +{ +  const char *common_progs; +  DBusString servicedir_path; + +  if (!_dbus_string_init (&servicedir_path)) +    return FALSE; + +  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR";")) +        goto oom; + +  common_progs = _dbus_getenv ("CommonProgramFiles"); + +  if (common_progs != NULL) +    { +      if (!_dbus_string_append (&servicedir_path, common_progs)) +        goto oom; + +      if (!_dbus_string_append (&servicedir_path, ";")) +        goto oom; +    } + +  if (!split_paths_and_append (&servicedir_path,  +                               DBUS_STANDARD_SESSION_SERVICEDIR,  +                               dirs)) +    goto oom; + +  _dbus_string_free (&servicedir_path);   +  return TRUE; + + oom: +  _dbus_string_free (&servicedir_path); +  return FALSE; +} + +_DBUS_DEFINE_GLOBAL_LOCK (atomic); + +/** + * Atomically increments an integer + * + * @param atomic pointer to the integer to increment + * @returns the value before incrementing + * + */ +dbus_int32_t +_dbus_atomic_inc (DBusAtomic *atomic) +{ +  // +/- 1 is needed here! +  return InterlockedIncrement (&atomic->value) - 1; +} + +/** + * Atomically decrement an integer + * + * @param atomic pointer to the integer to decrement + * @returns the value before decrementing + * + */ +dbus_int32_t +_dbus_atomic_dec (DBusAtomic *atomic) +{ +  // +/- 1 is needed here! +  return InterlockedDecrement (&atomic->value) + 1; +} + +#endif /* asserts or tests enabled */ + +/** @} end of sysdeps-win */ + +/* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h new file mode 100644 index 00000000..2bfb2a31 --- /dev/null +++ b/dbus/dbus-sysdeps-win.h @@ -0,0 +1,174 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation) + *  + * Copyright (C) 2002, 2003  Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2005 Novell, Inc. + * + * Licensed under the Academic Free License version 2.1 + *  + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#ifndef DBUS_SYSDEPS_WIN_H +#define DBUS_SYSDEPS_WIN_H + +#define _WINSOCKAPI_ + +#include "dbus-hash.h" +#include "dbus-string.h" +#include <ctype.h> +#include <malloc.h> +#include <windows.h> + +#include <aclapi.h> +#include <lm.h> +#include <io.h> +#include <share.h> +#include <direct.h> + +#define mkdir(path, mode) _mkdir (path) + +#ifndef DBUS_WINCE +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#endif + +/* Declarations missing in mingw's headers */ +extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR  StringSid, PSID *Sid); +extern BOOL WINAPI ConvertSidToStringSidA (PSID Sid, LPSTR *StringSid); + + +#define DBUS_CONSOLE_DIR "/var/run/console/" + +typedef struct +  { +    int fd;               /* File descriptor, SOCKET or file HANDLE */ +    int port_file_fd;     /* File descriptor for file containing +                           * port number for "pseudo-unix" sockets +                           */ +    DBusString port_file; /* File name for said file */ +    dbus_bool_t close_on_exec; +    dbus_bool_t non_blocking; +    int is_used;  +  } +DBusSocket; + +extern DBusSocket *win_fds; +extern int win32_n_fds; + + +void _dbus_win_startup_winsock (void); +void _dbus_win_warn_win_error  (const char *message, +                                int         code); +extern const char* _dbus_lm_strerror  (int error_number); + + +dbus_bool_t +fill_win_user_info_from_uid (dbus_uid_t    uid, +                             DBusUserInfo *info, +                             DBusError    *error); +dbus_bool_t +fill_win_user_info_from_name (wchar_t      *wname, +                              DBusUserInfo *info, +                              DBusError    *error); + +dbus_bool_t _dbus_win_account_to_sid (const wchar_t *waccount, +                                      void         **ppsid, +                                      DBusError     *error); + +dbus_bool_t +_dbus_win32_sid_to_name_and_domain (dbus_uid_t  uid, +                                    wchar_t   **wname, +                                    wchar_t   **wdomain, +                                    DBusError  *error); + + +/* Don't define DBUS_CONSOLE_DIR on Win32 */ + +wchar_t    *_dbus_win_utf8_to_utf16 (const char  *str, +                                     DBusError   *error); +char       *_dbus_win_utf16_to_utf8 (const wchar_t *str, +                                     DBusError *error); + +void        _dbus_win_set_error_from_win_error (DBusError *error, int code); + +dbus_uid_t  _dbus_win_sid_to_uid_t (void        *psid); +dbus_bool_t _dbus_uid_t_to_win_sid (dbus_uid_t   uid, +                                    void       **ppsid); +dbus_bool_t +_dbus_account_to_win_sid (const wchar_t  *waccount, +                          void          **ppsid, +                          DBusError      *error); +dbus_bool_t +_dbus_win_sid_to_name_and_domain (dbus_uid_t uid, +                                  wchar_t  **wname, +                                  wchar_t  **wdomain, +                                  DBusError *error); + +typedef struct DBusFile DBusFile; + +dbus_bool_t _dbus_open_file (DBusFile   *file, +                             const char *filename, +                             int         oflag, +                             int         pmode); + +dbus_bool_t _dbus_close_file (DBusFile  *file, +                              DBusError *error); + + +int _dbus_read_file  (DBusFile   *file, +                      DBusString *buffer, +                      int         count); + +int _dbus_write_file (DBusFile         *file, +                      const DBusString *buffer, +                      int               start, +                      int               len); + +#define FDATA private_data +struct DBusFile +  { +    int FDATA; +  }; + + +void _dbus_handle_to_socket (int          handle, +                             DBusSocket **socket); +int  _dbus_socket_to_handle (DBusSocket  *socket); + +dbus_bool_t +fill_user_info (DBusUserInfo       *info, +                dbus_uid_t          uid, +                const DBusString   *username, +                DBusError          *error); + +// replace with a windows version +dbus_bool_t _dbus_open_unix_socket (int              *fd, +                                    DBusError        *error); +int _dbus_connect_unix_socket (const char     *path, +                               dbus_bool_t     abstract, +                               DBusError      *error); +int _dbus_listen_unix_socket  (const char     *path, +                               dbus_bool_t     abstract, +                               DBusError      *error); + +#endif + +/** @} end of sysdeps-win.h */ + + | 
