* dbus/dbus-sysdeps-win.c: disabled DBusUserInfo related code
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-util-win.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus
3  * 
4  * Copyright (C) 2002, 2003, 2004, 2005  Red Hat, Inc.
5  * Copyright (C) 2003 CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 /* #define ENABLE_DBUSGROUPINFO */
26
27 #ifdef ENABLE_DBUSGROUPINFO
28 typedef struct {
29     int gid;
30     char *groupname;
31 } DBusGroupInfo;
32 #endif
33
34 #undef open
35
36 #define STRSAFE_NO_DEPRECATE
37
38 #include "dbus-sysdeps.h"
39 #include "dbus-internals.h"
40 #include "dbus-protocol.h"
41 #include "dbus-string.h"
42 #include "dbus-sysdeps.h"
43 #include "dbus-sysdeps-win.h"
44 #include "dbus-memory.h"
45
46 #include <io.h>
47 #include <sys/stat.h>
48 #include <aclapi.h>
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <fcntl.h>
53
54 #ifdef __MINGW32__
55 /* save string functions version
56    using DBusString needs to much time because of uncommon api 
57 */ 
58 #define errno_t int
59
60 errno_t strcat_s(char *dest, int size, char *src) 
61 {
62   _dbus_assert(strlen(dest) + strlen(src) +1 <= size);
63   strcat(dest,src);
64   return 0;
65 }
66
67 errno_t strcpy_s(char *dest, int size, char *src)
68 {
69   _dbus_assert(strlen(src) +1 <= size);
70   strcpy(dest,src);  
71   return 0;
72 }
73 #endif
74
75 /**
76  * return the absolute path of the dbus installation 
77  *
78  * @param s buffer for installation path
79  * @param len length of buffer
80  * @returns #FALSE on failure
81  */
82 dbus_bool_t 
83 _dbus_get_install_root(char *s, int len)
84 {
85   char *p = NULL;
86   int ret = GetModuleFileName(NULL,s,len);
87   if ( ret == 0 
88     || ret == len && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
89     {
90       *s = '\0';
91       return FALSE;
92     }
93   else if ((p = strstr(s,"\\bin\\")))
94     {
95       *(p+1)= '\0';
96       return TRUE;
97     }
98   else
99     {
100       *s = '\0';
101       return FALSE;
102     }
103 }
104
105 /* 
106   find session.conf either from installation or build root according to 
107   the following path layout 
108     install-root/
109       bin/dbus-daemon[d].exe
110       etc/session.conf 
111
112     build-root/
113       bin/dbus-daemon[d].exe
114       bus/session.conf 
115 */             
116 dbus_bool_t 
117 _dbus_get_config_file_name(DBusString *config_file, char *s)
118 {
119   char path[MAX_PATH*2];
120   int path_size = sizeof(path);
121
122   if (!_dbus_get_install_root(path,path_size))
123     return FALSE;
124
125   strcat_s(path,path_size,"etc\\");
126   strcat_s(path,path_size,s);
127   if (_dbus_file_exists(path)) 
128     {
129       // find path from executable 
130       if (!_dbus_string_append (config_file, path))
131         return FALSE;
132     }
133   else 
134     {
135       if (!_dbus_get_install_root(path,path_size))
136         return FALSE;
137       strcat_s(path,path_size,"bus\\");
138       strcat_s(path,path_size,s);
139   
140       if (_dbus_file_exists(path)) 
141         {
142           if (!_dbus_string_append (config_file, path))
143             return FALSE;
144         }
145     }
146   return TRUE;
147 }    
148     
149 /**
150  * Does the chdir, fork, setsid, etc. to become a daemon process.
151  *
152  * @param pidfile #NULL, or pidfile to create
153  * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
154  * @param error return location for errors
155  * @returns #FALSE on failure
156  */
157 dbus_bool_t
158 _dbus_become_daemon (const DBusString *pidfile,
159                      DBusPipe         *print_pid_pipe,
160                      DBusError        *error)
161 {
162   return TRUE;
163 }
164
165 /**
166  * Creates a file containing the process ID.
167  *
168  * @param filename the filename to write to
169  * @param pid our process ID
170  * @param error return location for errors
171  * @returns #FALSE on failure
172  */
173 dbus_bool_t
174 _dbus_write_pid_file (const DBusString *filename,
175                       unsigned long     pid,
176                       DBusError        *error)
177 {
178   const char *cfilename;
179   DBusFile file;
180   FILE *f;
181
182   cfilename = _dbus_string_get_const_data (filename);
183
184   if (!_dbus_file_open(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644))
185     {
186       dbus_set_error (error, _dbus_error_from_errno (errno),
187                       "Failed to open \"%s\": %s", cfilename,
188                       _dbus_strerror (errno));
189       return FALSE;
190     }
191
192   if ((f = fdopen (file.FDATA, "w")) == NULL)
193     {
194       dbus_set_error (error, _dbus_error_from_errno (errno),
195                       "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno));
196       _dbus_file_close (&file, NULL);
197       return FALSE;
198     }
199
200   if (fprintf (f, "%lu\n", pid) < 0)
201     {
202       dbus_set_error (error, _dbus_error_from_errno (errno),
203                       "Failed to write to \"%s\": %s", cfilename,
204                       _dbus_strerror (errno));
205
206       fclose (f);
207       return FALSE;
208     }
209
210   if (fclose (f) == EOF)
211     {
212       dbus_set_error (error, _dbus_error_from_errno (errno),
213                       "Failed to close \"%s\": %s", cfilename,
214                       _dbus_strerror (errno));
215       return FALSE;
216     }
217
218   return TRUE;
219 }
220
221 /**
222  * Verify that after the fork we can successfully change to this user.
223  *
224  * @param user the username given in the daemon configuration
225  * @returns #TRUE if username is valid
226  */
227 dbus_bool_t
228 _dbus_verify_daemon_user (const char *user)
229 {
230   return TRUE;
231 }
232
233 /**
234  * Changes the user and group the bus is running as.
235  *
236  * @param user the user to become
237  * @param error return location for errors
238  * @returns #FALSE on failure
239  */
240 dbus_bool_t
241 _dbus_change_to_daemon_user  (const char    *user,
242                               DBusError     *error)
243 {
244   return TRUE;
245 }
246
247 /**
248  * Changes the user and group the bus is running as.
249  *
250  * @param uid the new user ID
251  * @param gid the new group ID
252  * @param error return location for errors
253  * @returns #FALSE on failure
254  */
255 dbus_bool_t
256 _dbus_change_identity  (dbus_uid_t     uid,
257                         dbus_gid_t     gid,
258                         DBusError     *error)
259 {
260   return TRUE;
261 }
262
263 /** Checks if user is at the console
264 *
265 * @param username user to check
266 * @param error return location for errors
267 * @returns #TRUE is the user is at the consolei and there are no errors
268 */
269 dbus_bool_t
270 _dbus_user_at_console(const char *username,
271                       DBusError  *error)
272 {
273 #ifdef DBUS_WINCE
274         return TRUE;
275 #else
276   dbus_bool_t retval = FALSE;
277   wchar_t *wusername;
278   DWORD sid_length;
279   PSID user_sid, console_user_sid;
280   HWINSTA winsta;
281
282   wusername = _dbus_win_utf8_to_utf16 (username, error);
283   if (!wusername)
284     return FALSE;
285
286   if (!_dbus_win_account_to_sid (wusername, &user_sid, error))
287     goto out0;
288
289   /* Now we have the SID for username. Get the SID of the
290    * user at the "console" (window station WinSta0)
291    */
292   if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL)))
293     {
294       _dbus_win_set_error_from_win_error (error, GetLastError ());
295       goto out2;
296     }
297
298   sid_length = 0;
299   GetUserObjectInformation (winsta, UOI_USER_SID,
300                             NULL, 0, &sid_length);
301   if (sid_length == 0)
302     {
303       /* Nobody is logged on */
304       goto out2;
305     }
306
307   if (sid_length < 0 || sid_length > 1000)
308     {
309       dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length");
310       goto out3;
311     }
312
313   console_user_sid = dbus_malloc (sid_length);
314   if (!console_user_sid)
315     {
316       _DBUS_SET_OOM (error);
317       goto out3;
318     }
319
320   if (!GetUserObjectInformation (winsta, UOI_USER_SID,
321                                  console_user_sid, sid_length, &sid_length))
322     {
323       _dbus_win_set_error_from_win_error (error, GetLastError ());
324       goto out4;
325     }
326
327   if (!IsValidSid (console_user_sid))
328     {
329       dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
330       goto out4;
331     }
332
333   retval = EqualSid (user_sid, console_user_sid);
334
335 out4:
336   dbus_free (console_user_sid);
337 out3:
338   CloseWindowStation (winsta);
339 out2:
340   dbus_free (user_sid);
341 out0:
342   dbus_free (wusername);
343
344   return retval;
345 #endif //DBUS_WINCE
346 }
347
348 /**
349  * Removes a directory; Directory must be empty
350  * 
351  * @param filename directory filename
352  * @param error initialized error object
353  * @returns #TRUE on success
354  */
355 dbus_bool_t
356 _dbus_delete_directory (const DBusString *filename,
357                         DBusError        *error)
358 {
359   const char *filename_c;
360
361   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
362
363   filename_c = _dbus_string_get_const_data (filename);
364
365   if (rmdir (filename_c) != 0)
366     {
367       dbus_set_error (error, DBUS_ERROR_FAILED,
368                       "Failed to remove directory %s: %s\n",
369                       filename_c, _dbus_strerror (errno));
370       return FALSE;
371     }
372
373   return TRUE;
374 }
375
376 /** Installs a signal handler
377  *
378  * @param sig the signal to handle
379  * @param handler the handler
380  */
381 void
382 _dbus_set_signal_handler (int               sig,
383                           DBusSignalHandler handler)
384 {
385   _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n");
386 }
387
388 /** Checks if a file exists
389 *
390 * @param file full path to the file
391 * @returns #TRUE if file exists
392 */
393 dbus_bool_t 
394 _dbus_file_exists (const char *file)
395 {
396   HANDLE h = CreateFile(
397           file, /* LPCTSTR lpFileName*/
398           0, /* DWORD dwDesiredAccess */
399           0, /* DWORD dwShareMode*/
400           NULL, /* LPSECURITY_ATTRIBUTES lpSecurityAttributes */
401           OPEN_EXISTING, /* DWORD dwCreationDisposition */
402           FILE_ATTRIBUTE_NORMAL, /* DWORD dwFlagsAndAttributes */
403           NULL /* HANDLE hTemplateFile */
404         );
405
406     /* file not found, use local copy of session.conf  */
407     if (h != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND)
408       {
409         CloseHandle(h);
410         return TRUE;
411       }
412     else
413         return FALSE;  
414 }
415
416 /**
417  * stat() wrapper.
418  *
419  * @param filename the filename to stat
420  * @param statbuf the stat info to fill in
421  * @param error return location for error
422  * @returns #FALSE if error was set
423  */
424 dbus_bool_t
425 _dbus_stat(const DBusString *filename,
426            DBusStat         *statbuf,
427            DBusError        *error)
428 {
429 #ifdef DBUS_WINCE
430         return TRUE;
431         //TODO
432 #else
433   const char *filename_c;
434 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
435
436   struct stat sb;
437 #else
438
439   WIN32_FILE_ATTRIBUTE_DATA wfad;
440   char *lastdot;
441   DWORD rc;
442   PSID owner_sid, group_sid;
443   PSECURITY_DESCRIPTOR sd;
444 #endif
445
446   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
447
448   filename_c = _dbus_string_get_const_data (filename);
449
450   if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad))
451     {
452       _dbus_win_set_error_from_win_error (error, GetLastError ());
453       return FALSE;
454     }
455
456   if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
457     statbuf->mode = _S_IFDIR;
458   else
459     statbuf->mode = _S_IFREG;
460
461   statbuf->mode |= _S_IREAD;
462   if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
463     statbuf->mode |= _S_IWRITE;
464
465   lastdot = strrchr (filename_c, '.');
466   if (lastdot && stricmp (lastdot, ".exe") == 0)
467     statbuf->mode |= _S_IEXEC;
468
469   statbuf->mode |= (statbuf->mode & 0700) >> 3;
470   statbuf->mode |= (statbuf->mode & 0700) >> 6;
471
472   statbuf->nlink = 1;
473
474   sd = NULL;
475   rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
476                              OWNER_SECURITY_INFORMATION |
477                              GROUP_SECURITY_INFORMATION,
478                              &owner_sid, &group_sid,
479                              NULL, NULL,
480                              &sd);
481   if (rc != ERROR_SUCCESS)
482     {
483       _dbus_win_set_error_from_win_error (error, rc);
484       if (sd != NULL)
485         LocalFree (sd);
486       return FALSE;
487     }
488
489   statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
490   statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
491
492   LocalFree (sd);
493
494   statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow;
495
496   statbuf->atime =
497     (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) +
498      wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
499
500   statbuf->mtime =
501     (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) +
502      wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
503
504   statbuf->ctime =
505     (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) +
506      wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
507
508   return TRUE;
509 #endif //DBUS_WINCE
510 }
511
512
513 #ifdef HAVE_DIRENT_H
514
515 // mingw ships with dirent.h
516 #include <dirent.h>
517 #define _dbus_opendir opendir
518 #define _dbus_readdir readdir
519 #define _dbus_closedir closedir
520
521 #else
522
523 #ifdef HAVE_IO_H
524 #include <io.h> // win32 file functions
525 #endif
526
527 #include <sys/types.h>
528 #include <stdlib.h>
529
530 /* This file is part of the KDE project
531 Copyright (C) 2000 Werner Almesberger
532
533 libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir
534
535 This program is free software; you can redistribute it and/or
536 modify it under the terms of the GNU Library General Public
537 License as published by the Free Software Foundation; either
538 version 2 of the License, or (at your option) any later version.
539
540 This program is distributed in the hope that it will be useful,
541 but WITHOUT ANY WARRANTY; without even the implied warranty of
542 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
543 Library General Public License for more details.
544
545 You should have received a copy of the GNU Library General Public License
546 along with this program; see the file COPYING.  If not, write to
547 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
548 Boston, MA 02110-1301, USA.
549 */
550 #define HAVE_NO_D_NAMLEN        /* no struct dirent->d_namlen */
551 #define HAVE_DD_LOCK            /* have locking mechanism */
552
553 #define MAXNAMLEN 255           /* sizeof(struct dirent.d_name)-1 */
554
555 #define __dirfd(dir) (dir)->dd_fd
556
557 /* struct dirent - same as Unix */
558 struct dirent
559   {
560     long d_ino;                    /* inode (always 1 in WIN32) */
561     off_t d_off;                /* offset to this dirent */
562     unsigned short d_reclen;    /* length of d_name */
563     char d_name[_MAX_FNAME+1];    /* filename (null terminated) */
564   };
565
566 /* typedef DIR - not the same as Unix */
567 typedef struct
568   {
569     long handle;                /* _findfirst/_findnext handle */
570     short offset;                /* offset into directory */
571     short finished;             /* 1 if there are not more files */
572     struct _finddata_t fileinfo;  /* from _findfirst/_findnext */
573     char *dir;                  /* the dir we are reading */
574     struct dirent dent;         /* the dirent to return */
575   }
576 DIR;
577
578 /**********************************************************************
579 * Implement dirent-style opendir/readdir/closedir on Window 95/NT
580 *
581 * Functions defined are opendir(), readdir() and closedir() with the
582 * same prototypes as the normal dirent.h implementation.
583 *
584 * Does not implement telldir(), seekdir(), rewinddir() or scandir().
585 * The dirent struct is compatible with Unix, except that d_ino is
586 * always 1 and d_off is made up as we go along.
587 *
588 * The DIR typedef is not compatible with Unix.
589 **********************************************************************/
590
591 DIR * _dbus_opendir(const char *dir)
592 {
593   DIR *dp;
594   char *filespec;
595   long handle;
596   int index;
597
598   filespec = malloc(strlen(dir) + 2 + 1);
599   strcpy(filespec, dir);
600   index = strlen(filespec) - 1;
601   if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
602     filespec[index] = '\0';
603   strcat(filespec, "\\*");
604
605   dp = (DIR *)malloc(sizeof(DIR));
606   dp->offset = 0;
607   dp->finished = 0;
608   dp->dir = strdup(dir);
609
610   if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0)
611     {
612       if (errno == ENOENT)
613         dp->finished = 1;
614       else
615         return NULL;
616     }
617
618   dp->handle = handle;
619   free(filespec);
620
621   return dp;
622 }
623
624 struct dirent * _dbus_readdir(DIR *dp)
625   {
626     if (!dp || dp->finished)
627       return NULL;
628
629     if (dp->offset != 0)
630       {
631         if (_findnext(dp->handle, &(dp->fileinfo)) < 0)
632           {
633             dp->finished = 1;
634             errno = 0;
635             return NULL;
636           }
637       }
638     dp->offset++;
639
640     strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
641     dp->dent.d_ino = 1;
642     dp->dent.d_reclen = strlen(dp->dent.d_name);
643     dp->dent.d_off = dp->offset;
644
645     return &(dp->dent);
646   }
647
648
649 int _dbus_closedir(DIR *dp)
650 {
651   if (!dp)
652     return 0;
653   _findclose(dp->handle);
654   if (dp->dir)
655     free(dp->dir);
656   if (dp)
657     free(dp);
658
659   return 0;
660 }
661
662 #endif //#ifdef HAVE_DIRENT_H
663
664 /**
665  * Internals of directory iterator
666  */
667 struct DBusDirIter
668   {
669     DIR *d; /**< The DIR* from opendir() */
670
671   };
672
673 /**
674  * Open a directory to iterate over.
675  *
676  * @param filename the directory name
677  * @param error exception return object or #NULL
678  * @returns new iterator, or #NULL on error
679  */
680 DBusDirIter*
681 _dbus_directory_open (const DBusString *filename,
682                       DBusError        *error)
683 {
684   DIR *d;
685   DBusDirIter *iter;
686   const char *filename_c;
687
688   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
689
690   filename_c = _dbus_string_get_const_data (filename);
691
692   d = _dbus_opendir (filename_c);
693   if (d == NULL)
694     {
695       dbus_set_error (error, _dbus_error_from_errno (errno),
696                       "Failed to read directory \"%s\": %s",
697                       filename_c,
698                       _dbus_strerror (errno));
699       return NULL;
700     }
701   iter = dbus_new0 (DBusDirIter, 1);
702   if (iter == NULL)
703     {
704       _dbus_closedir (d);
705       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
706                       "Could not allocate memory for directory iterator");
707       return NULL;
708     }
709
710   iter->d = d;
711
712   return iter;
713 }
714
715 /**
716  * Get next file in the directory. Will not return "." or ".."  on
717  * UNIX. If an error occurs, the contents of "filename" are
718  * undefined. The error is never set if the function succeeds.
719  *
720  * @todo for thread safety, I think we have to use
721  * readdir_r(). (GLib has the same issue, should file a bug.)
722  *
723  * @param iter the iterator
724  * @param filename string to be set to the next file in the dir
725  * @param error return location for error
726  * @returns #TRUE if filename was filled in with a new filename
727  */
728 dbus_bool_t
729 _dbus_directory_get_next_file (DBusDirIter      *iter,
730                                DBusString       *filename,
731                                DBusError        *error)
732 {
733   struct dirent *ent;
734
735   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
736
737 again:
738   errno = 0;
739   ent = _dbus_readdir (iter->d);
740   if (ent == NULL)
741     {
742       if (errno != 0)
743         dbus_set_error (error,
744                         _dbus_error_from_errno (errno),
745                         "%s", _dbus_strerror (errno));
746       return FALSE;
747     }
748   else if (ent->d_name[0] == '.' &&
749            (ent->d_name[1] == '\0' ||
750             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
751     goto again;
752   else
753     {
754       _dbus_string_set_length (filename, 0);
755       if (!_dbus_string_append (filename, ent->d_name))
756         {
757           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
758                           "No memory to read directory entry");
759           return FALSE;
760         }
761       else
762         return TRUE;
763     }
764 }
765
766 /**
767  * Closes a directory iteration.
768  */
769 void
770 _dbus_directory_close (DBusDirIter *iter)
771 {
772   _dbus_closedir (iter->d);
773   dbus_free (iter);
774 }
775
776 /**
777  * Checks whether the filename is an absolute path
778  *
779  * @param filename the filename
780  * @returns #TRUE if an absolute path
781  */
782 dbus_bool_t
783 _dbus_path_is_absolute (const DBusString *filename)
784 {
785   if (_dbus_string_get_length (filename) > 0)
786     return _dbus_string_get_byte (filename, 1) == ':'
787            || _dbus_string_get_byte (filename, 0) == '\\'
788            || _dbus_string_get_byte (filename, 0) == '/';
789   else
790     return FALSE;
791 }
792
793 #ifdef ENABLE_DBUSGROPINFO
794 static dbus_bool_t
795 fill_group_info(DBusGroupInfo    *info,
796                 dbus_gid_t        gid,
797                 const DBusString *groupname,
798                 DBusError        *error)
799 {
800   const char *group_c_str;
801
802   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
803   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
804
805   if (groupname)
806     group_c_str = _dbus_string_get_const_data (groupname);
807   else
808     group_c_str = NULL;
809
810   if (group_c_str)
811     {
812       PSID group_sid;
813       wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error);
814
815       if (!wgroupname)
816         return FALSE;
817
818       if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error))
819         {
820           dbus_free (wgroupname);
821           return FALSE;
822         }
823
824       info->gid = _dbus_win_sid_to_uid_t (group_sid);
825       info->groupname = _dbus_strdup (group_c_str);
826
827       dbus_free (group_sid);
828       dbus_free (wgroupname);
829
830       return TRUE;
831     }
832   else
833     {
834       dbus_bool_t retval = FALSE;
835       wchar_t *wname, *wdomain;
836       char *name, *domain;
837
838       info->gid = gid;
839
840       if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error))
841         return FALSE;
842
843       name = _dbus_win_utf16_to_utf8 (wname, error);
844       if (!name)
845         goto out0;
846
847       domain = _dbus_win_utf16_to_utf8 (wdomain, error);
848       if (!domain)
849         goto out1;
850
851       info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
852
853       strcpy (info->groupname, domain);
854       strcat (info->groupname, "\\");
855       strcat (info->groupname, name);
856
857       retval = TRUE;
858
859       dbus_free (domain);
860 out1:
861       dbus_free (name);
862 out0:
863       dbus_free (wname);
864       dbus_free (wdomain);
865
866       return retval;
867     }
868 }
869
870 /**
871  * Initializes the given DBusGroupInfo struct
872  * with information about the given group ID.
873  *
874  * @param info the group info struct
875  * @param gid group ID
876  * @param error the error return
877  * @returns #FALSE if error is set
878  */
879 dbus_bool_t
880 _dbus_group_info_fill_gid (DBusGroupInfo *info,
881                            dbus_gid_t     gid,
882                            DBusError     *error)
883 {
884   return fill_group_info (info, gid, NULL, error);
885 }
886
887 /**
888  * Initializes the given DBusGroupInfo struct
889  * with information about the given group name.
890  *
891  * @param info the group info struct
892  * @param groupname name of group
893  * @param error the error return
894  * @returns #FALSE if error is set
895  */
896 dbus_bool_t
897 _dbus_group_info_fill (DBusGroupInfo    *info,
898                        const DBusString *groupname,
899                        DBusError        *error)
900 {
901   return fill_group_info (info, DBUS_GID_UNSET,
902                           groupname, error);
903 }
904 #endif
905
906 /** @} */ /* End of DBusInternalsUtils functions */
907
908 /**
909  * @addtogroup DBusString
910  *
911  * @{
912  */
913 /**
914  * Get the directory name from a complete filename
915  * @param filename the filename
916  * @param dirname string to append directory name to
917  * @returns #FALSE if no memory
918  */
919 dbus_bool_t
920 _dbus_string_get_dirname(const DBusString *filename,
921                          DBusString       *dirname)
922 {
923   int sep;
924
925   _dbus_assert (filename != dirname);
926   _dbus_assert (filename != NULL);
927   _dbus_assert (dirname != NULL);
928
929   /* Ignore any separators on the end */
930   sep = _dbus_string_get_length (filename);
931   if (sep == 0)
932     return _dbus_string_append (dirname, "."); /* empty string passed in */
933
934   while (sep > 0 &&
935          (_dbus_string_get_byte (filename, sep - 1) == '/' ||
936           _dbus_string_get_byte (filename, sep - 1) == '\\'))
937     --sep;
938
939   _dbus_assert (sep >= 0);
940
941   if (sep == 0 ||
942       (sep == 2 &&
943        _dbus_string_get_byte (filename, 1) == ':' &&
944        isalpha (_dbus_string_get_byte (filename, 0))))
945     return _dbus_string_copy_len (filename, 0, sep + 1,
946                                   dirname, _dbus_string_get_length (dirname));
947
948   {
949     int sep1, sep2;
950     _dbus_string_find_byte_backward (filename, sep, '/', &sep1);
951     _dbus_string_find_byte_backward (filename, sep, '\\', &sep2);
952
953     sep = MAX (sep1, sep2);
954   }
955   if (sep < 0)
956     return _dbus_string_append (dirname, ".");
957
958   while (sep > 0 &&
959          (_dbus_string_get_byte (filename, sep - 1) == '/' ||
960           _dbus_string_get_byte (filename, sep - 1) == '\\'))
961     --sep;
962
963   _dbus_assert (sep >= 0);
964
965   if ((sep == 0 ||
966        (sep == 2 &&
967         _dbus_string_get_byte (filename, 1) == ':' &&
968         isalpha (_dbus_string_get_byte (filename, 0))))
969       &&
970       (_dbus_string_get_byte (filename, sep) == '/' ||
971        _dbus_string_get_byte (filename, sep) == '\\'))
972     return _dbus_string_copy_len (filename, 0, sep + 1,
973                                   dirname, _dbus_string_get_length (dirname));
974   else
975     return _dbus_string_copy_len (filename, 0, sep - 0,
976                                   dirname, _dbus_string_get_length (dirname));
977 }
978
979 /** @} */ /* DBusString stuff */
980