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