1998-06-11 01:21:14 +02:00
|
|
|
/* GLIB - Library of useful routines for C programming
|
1998-09-06 02:31:48 +02:00
|
|
|
* Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
|
1998-06-11 01:21:14 +02:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
2000-07-26 13:02:02 +02:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
1998-06-11 01:21:14 +02:00
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 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
|
2000-07-26 13:02:02 +02:00
|
|
|
* Lesser General Public License for more details.
|
1998-06-11 01:21:14 +02:00
|
|
|
*
|
2000-07-26 13:02:02 +02:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2014-01-23 12:58:29 +01:00
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
1998-06-11 01:21:14 +02:00
|
|
|
*/
|
1998-11-01 02:32:59 +01:00
|
|
|
|
1999-02-24 07:14:27 +01:00
|
|
|
/*
|
2000-07-26 13:02:02 +02:00
|
|
|
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
1999-02-24 07:14:27 +01:00
|
|
|
* file for a list of people on the GLib Team. See the ChangeLog
|
|
|
|
* files for a list of changes. These files are distributed with
|
|
|
|
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
|
|
|
*/
|
|
|
|
|
1998-12-15 06:28:02 +01:00
|
|
|
/*
|
|
|
|
* MT safe for the unix part, FIXME: make the win32 part MT safe as well.
|
|
|
|
*/
|
|
|
|
|
2002-12-04 02:27:44 +01:00
|
|
|
#include "config.h"
|
2015-11-09 17:12:18 +01:00
|
|
|
|
|
|
|
#include "gutils.h"
|
1998-11-01 02:32:59 +01:00
|
|
|
|
1998-06-11 01:21:14 +02:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
1998-07-10 07:51:17 +02:00
|
|
|
#include <stdio.h>
|
2004-09-07 20:37:10 +02:00
|
|
|
#include <locale.h>
|
1998-06-11 01:21:14 +02:00
|
|
|
#include <string.h>
|
2006-07-06 22:30:16 +02:00
|
|
|
#include <ctype.h> /* For tolower() */
|
1998-09-08 06:10:30 +02:00
|
|
|
#include <errno.h>
|
2007-06-04 16:54:49 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
#ifdef G_OS_UNIX
|
1998-07-10 07:51:17 +02:00
|
|
|
#include <pwd.h>
|
Replace #ifdef HAVE_UNISTD_H checks with #ifdef G_OS_UNIX
In Windows development environments that have it, <unistd.h> is mostly
just a wrapper around several other native headers (in particular,
<io.h>, which contains read(), close(), etc, and <process.h>, which
contains getpid()). But given that some Windows dev environments don't
have <unistd.h>, everything that uses those functions on Windows
already needed to include the correct Windows header as well, and so
there is never any point to including <unistd.h> on Windows.
Also, remove some <unistd.h> includes (and a few others) that were
unnecessary even on unix.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:04:00 +02:00
|
|
|
#include <unistd.h>
|
removed dummy structure definitions for struct _GCache, _GTree, _GTimer,
Tue Oct 27 03:00:50 1998 Tim Janik <timj@gtk.org>
* glib.h: removed dummy structure definitions for struct _GCache,
_GTree, _GTimer, _GMemChunk, _GListAllocator and _GStringChunk.
* gutils.c: implement glib's inline functions _after_ all include
statements have been processed.
removed Tor's MAXPATHLEN check since there already was one supplied
further down in this file.
(LibMain): special cased the #ifdef __LCC__ case for NATIVE_WIN32,
since lcc maybe used on other platforms as well. why in hell is this
stuff required?
(g_get_any_init): for windows, if the user name is supplied, use it as
realname also.
in general, if there is no homedir specified, use the tmpdir that
we already figured.
* gtimer.c (g_timer_elapsed): changed a g_assert() statement to
g_return_if_fail().
* applied glib-tml-981020-0.patch for WIN32 portability, added some
comments and g_return_if_fail() statements, minor indentation fixes.
ChangeLog entry from Tor Lillqvist is appended.
* glib.h (struct dirent): use lower case structure members.
* glib.h:
* makefile.lcc:
* makefile.msc:
s/COMPILING_GLIB/GLIB_COMPILATION/
1998-10-20: Tor Lillqvist <tml@iki.fi>
* README.win32 glib.def gmodule.def
* glibconfig.h.win32 gmodule/gmoduleconf.h.win32:
New files for the Windows port. The .def files list exported
symbols for the Microsoft linker and compatibles.
* configure.in:
Added checks for some platform-dependent headers: pwd.h sys/param.h
sys/select.h sys/time.h sys/times.h unistd.h, and the function lstat.
* gerror.c:
Conditionalized inclusion of system-dependent headers. Changes
for Windows: no gdb to do a stack trace. Just call abort().
* glib.h:
Changes for Windows:
Added macros G_DIR_SEPARATOR, G_DIR_SEPARATOR_S for
platform-dependent file name syntax elements. Added macros
G_SEARCHPATH_SEPARATOR, G_SEARCHPATH_SEPARATOR_S for
platform-dependent search path syntax conventions.
Added pragmas for Microsoft C to make it more pedantic.
Marked GLib's global variables for export from DLL.
Added the function g_strescape that escapes backslashes.
Added functions g_path_is_absolute and g_path_skip_root to
handle platform-dependent file name syntax.
Added the function g_getenv that expands environment variables
that contain references to other environment variables, as is
typical on Windows NT.
Added the GIOChannel structure which is used to encapsulate the
IPC mechanism used by the GIMP's plug-ins, and possibly other
things later. On Unix a GIOChannel encapsulates just a file
descriptor. On Windows it contains a file handle from _pipe() and a
few other things related to the implementation of gdk_input_add
and GIMP plug-in communication. Subject to change.
Removed duplicate declarations of the version variables.
For the Microsoft compiler, declare own implementation of
ftruncate and the <dirent.h> functions.
* gmem.c:
Define a symbolic name for the profiling table size.
* gmessages.c:
Conditionalized inclusion of unistd.h. On Windows, output using
stdio to stdout.
* gscanner.c:
Conditionalized inclusion of unistd.h. Added changes for
Microsoft C. Added CR to the skipped character set. Added small
workaround for MSC compiler bug in g_scanner_cur_value.
* gstrfuncs.c:
Added the function g_strescape, which escapes the backslash
character. Needed especially when printing Windows filenames.
* gtimer.c:
Conditionalized inclusion of unistd.h and sys/time.h. Added
implementations for Windows.
* gutils.c:
Conditionalized inclusion of platform-dependent headers. Use
the platform-independent file name syntax macros.
Conditionalize code on platform-dependent features. Added the
functions g_path_is_absolute g_path_skip_root and g_getenv.
Added the GIOChannel-related functions. Added
compiler-dependent Unix compatibility functions for Windows.
* makefile.lcc makefile.msc:
New files. Compiler-specific makefiles for LCC-Win32 and
Microsoft C. Only Microsoft C is actually supported currently.
* testglib.c:
Added pathname check cases for Windows. Added workaround for
bug in the Microsoft runtime library. Improved some tests a bit.
Tue Oct 27 04:00:11 1998 Tim Janik <timj@gtk.org>
* testgmodule.c (main): changed the #ifdef WIN32 test to NATIVE_WIN32,
this needs to be more constistent throughout the code, do we go for
NATIVE_WIN32 or WIN32?
* gmodule.c (LibMain): special cased the #ifdef __LCC__ case for
NATIVE_WIN32, since lcc maybe used on other platforms as well.
* libgplugin_a.c (LibMain):
* libgplugin_b.c (LibMain):
likewise. not sure i like this special requirement for lcc in here.
* gmodule-dl.c (_g_module_build_path):
feature empty "" directories and prepend the module name with "lib".
* gmodule-dld.c (_g_module_build_path):
* gmodule-win32.c (_g_module_build_path):
feature empty "" directories.
* we need some more magic in the _g_module_build_path variants
so we don't append/prepend lib and .so, .sl or .dll for those names
that already contain it.
* applied patch from Tor Lillqvist for g_module_build_path() and
windows support.
1998-10-20: Tor Lillqvist <tml@iki.fi>
* gmodule/gmodule-win32.c:
New file.
* gmodule/gmodule.c gmodule/gmodule.h:
Added the funcion g_module_build_path that builds the path to
a module file, decorating the name according to the system's
conventions. Added the Windows implementation.
* gmodule/libgplugin_a.c gmodule/libgplugin_b.c:
Added LibMain for LCC-Win32.
* gmodule/testgmodule.c:
Handle Windows dll names.
1998-10-27 05:11:34 +01:00
|
|
|
#endif
|
1998-07-10 07:51:17 +02:00
|
|
|
#include <sys/types.h>
|
removed dummy structure definitions for struct _GCache, _GTree, _GTimer,
Tue Oct 27 03:00:50 1998 Tim Janik <timj@gtk.org>
* glib.h: removed dummy structure definitions for struct _GCache,
_GTree, _GTimer, _GMemChunk, _GListAllocator and _GStringChunk.
* gutils.c: implement glib's inline functions _after_ all include
statements have been processed.
removed Tor's MAXPATHLEN check since there already was one supplied
further down in this file.
(LibMain): special cased the #ifdef __LCC__ case for NATIVE_WIN32,
since lcc maybe used on other platforms as well. why in hell is this
stuff required?
(g_get_any_init): for windows, if the user name is supplied, use it as
realname also.
in general, if there is no homedir specified, use the tmpdir that
we already figured.
* gtimer.c (g_timer_elapsed): changed a g_assert() statement to
g_return_if_fail().
* applied glib-tml-981020-0.patch for WIN32 portability, added some
comments and g_return_if_fail() statements, minor indentation fixes.
ChangeLog entry from Tor Lillqvist is appended.
* glib.h (struct dirent): use lower case structure members.
* glib.h:
* makefile.lcc:
* makefile.msc:
s/COMPILING_GLIB/GLIB_COMPILATION/
1998-10-20: Tor Lillqvist <tml@iki.fi>
* README.win32 glib.def gmodule.def
* glibconfig.h.win32 gmodule/gmoduleconf.h.win32:
New files for the Windows port. The .def files list exported
symbols for the Microsoft linker and compatibles.
* configure.in:
Added checks for some platform-dependent headers: pwd.h sys/param.h
sys/select.h sys/time.h sys/times.h unistd.h, and the function lstat.
* gerror.c:
Conditionalized inclusion of system-dependent headers. Changes
for Windows: no gdb to do a stack trace. Just call abort().
* glib.h:
Changes for Windows:
Added macros G_DIR_SEPARATOR, G_DIR_SEPARATOR_S for
platform-dependent file name syntax elements. Added macros
G_SEARCHPATH_SEPARATOR, G_SEARCHPATH_SEPARATOR_S for
platform-dependent search path syntax conventions.
Added pragmas for Microsoft C to make it more pedantic.
Marked GLib's global variables for export from DLL.
Added the function g_strescape that escapes backslashes.
Added functions g_path_is_absolute and g_path_skip_root to
handle platform-dependent file name syntax.
Added the function g_getenv that expands environment variables
that contain references to other environment variables, as is
typical on Windows NT.
Added the GIOChannel structure which is used to encapsulate the
IPC mechanism used by the GIMP's plug-ins, and possibly other
things later. On Unix a GIOChannel encapsulates just a file
descriptor. On Windows it contains a file handle from _pipe() and a
few other things related to the implementation of gdk_input_add
and GIMP plug-in communication. Subject to change.
Removed duplicate declarations of the version variables.
For the Microsoft compiler, declare own implementation of
ftruncate and the <dirent.h> functions.
* gmem.c:
Define a symbolic name for the profiling table size.
* gmessages.c:
Conditionalized inclusion of unistd.h. On Windows, output using
stdio to stdout.
* gscanner.c:
Conditionalized inclusion of unistd.h. Added changes for
Microsoft C. Added CR to the skipped character set. Added small
workaround for MSC compiler bug in g_scanner_cur_value.
* gstrfuncs.c:
Added the function g_strescape, which escapes the backslash
character. Needed especially when printing Windows filenames.
* gtimer.c:
Conditionalized inclusion of unistd.h and sys/time.h. Added
implementations for Windows.
* gutils.c:
Conditionalized inclusion of platform-dependent headers. Use
the platform-independent file name syntax macros.
Conditionalize code on platform-dependent features. Added the
functions g_path_is_absolute g_path_skip_root and g_getenv.
Added the GIOChannel-related functions. Added
compiler-dependent Unix compatibility functions for Windows.
* makefile.lcc makefile.msc:
New files. Compiler-specific makefiles for LCC-Win32 and
Microsoft C. Only Microsoft C is actually supported currently.
* testglib.c:
Added pathname check cases for Windows. Added workaround for
bug in the Microsoft runtime library. Improved some tests a bit.
Tue Oct 27 04:00:11 1998 Tim Janik <timj@gtk.org>
* testgmodule.c (main): changed the #ifdef WIN32 test to NATIVE_WIN32,
this needs to be more constistent throughout the code, do we go for
NATIVE_WIN32 or WIN32?
* gmodule.c (LibMain): special cased the #ifdef __LCC__ case for
NATIVE_WIN32, since lcc maybe used on other platforms as well.
* libgplugin_a.c (LibMain):
* libgplugin_b.c (LibMain):
likewise. not sure i like this special requirement for lcc in here.
* gmodule-dl.c (_g_module_build_path):
feature empty "" directories and prepend the module name with "lib".
* gmodule-dld.c (_g_module_build_path):
* gmodule-win32.c (_g_module_build_path):
feature empty "" directories.
* we need some more magic in the _g_module_build_path variants
so we don't append/prepend lib and .so, .sl or .dll for those names
that already contain it.
* applied patch from Tor Lillqvist for g_module_build_path() and
windows support.
1998-10-20: Tor Lillqvist <tml@iki.fi>
* gmodule/gmodule-win32.c:
New file.
* gmodule/gmodule.c gmodule/gmodule.h:
Added the funcion g_module_build_path that builds the path to
a module file, decorating the name according to the system's
conventions. Added the Windows implementation.
* gmodule/libgplugin_a.c gmodule/libgplugin_b.c:
Added LibMain for LCC-Win32.
* gmodule/testgmodule.c:
Handle Windows dll names.
1998-10-27 05:11:34 +01:00
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
1998-07-10 07:51:17 +02:00
|
|
|
#include <sys/param.h>
|
removed dummy structure definitions for struct _GCache, _GTree, _GTimer,
Tue Oct 27 03:00:50 1998 Tim Janik <timj@gtk.org>
* glib.h: removed dummy structure definitions for struct _GCache,
_GTree, _GTimer, _GMemChunk, _GListAllocator and _GStringChunk.
* gutils.c: implement glib's inline functions _after_ all include
statements have been processed.
removed Tor's MAXPATHLEN check since there already was one supplied
further down in this file.
(LibMain): special cased the #ifdef __LCC__ case for NATIVE_WIN32,
since lcc maybe used on other platforms as well. why in hell is this
stuff required?
(g_get_any_init): for windows, if the user name is supplied, use it as
realname also.
in general, if there is no homedir specified, use the tmpdir that
we already figured.
* gtimer.c (g_timer_elapsed): changed a g_assert() statement to
g_return_if_fail().
* applied glib-tml-981020-0.patch for WIN32 portability, added some
comments and g_return_if_fail() statements, minor indentation fixes.
ChangeLog entry from Tor Lillqvist is appended.
* glib.h (struct dirent): use lower case structure members.
* glib.h:
* makefile.lcc:
* makefile.msc:
s/COMPILING_GLIB/GLIB_COMPILATION/
1998-10-20: Tor Lillqvist <tml@iki.fi>
* README.win32 glib.def gmodule.def
* glibconfig.h.win32 gmodule/gmoduleconf.h.win32:
New files for the Windows port. The .def files list exported
symbols for the Microsoft linker and compatibles.
* configure.in:
Added checks for some platform-dependent headers: pwd.h sys/param.h
sys/select.h sys/time.h sys/times.h unistd.h, and the function lstat.
* gerror.c:
Conditionalized inclusion of system-dependent headers. Changes
for Windows: no gdb to do a stack trace. Just call abort().
* glib.h:
Changes for Windows:
Added macros G_DIR_SEPARATOR, G_DIR_SEPARATOR_S for
platform-dependent file name syntax elements. Added macros
G_SEARCHPATH_SEPARATOR, G_SEARCHPATH_SEPARATOR_S for
platform-dependent search path syntax conventions.
Added pragmas for Microsoft C to make it more pedantic.
Marked GLib's global variables for export from DLL.
Added the function g_strescape that escapes backslashes.
Added functions g_path_is_absolute and g_path_skip_root to
handle platform-dependent file name syntax.
Added the function g_getenv that expands environment variables
that contain references to other environment variables, as is
typical on Windows NT.
Added the GIOChannel structure which is used to encapsulate the
IPC mechanism used by the GIMP's plug-ins, and possibly other
things later. On Unix a GIOChannel encapsulates just a file
descriptor. On Windows it contains a file handle from _pipe() and a
few other things related to the implementation of gdk_input_add
and GIMP plug-in communication. Subject to change.
Removed duplicate declarations of the version variables.
For the Microsoft compiler, declare own implementation of
ftruncate and the <dirent.h> functions.
* gmem.c:
Define a symbolic name for the profiling table size.
* gmessages.c:
Conditionalized inclusion of unistd.h. On Windows, output using
stdio to stdout.
* gscanner.c:
Conditionalized inclusion of unistd.h. Added changes for
Microsoft C. Added CR to the skipped character set. Added small
workaround for MSC compiler bug in g_scanner_cur_value.
* gstrfuncs.c:
Added the function g_strescape, which escapes the backslash
character. Needed especially when printing Windows filenames.
* gtimer.c:
Conditionalized inclusion of unistd.h and sys/time.h. Added
implementations for Windows.
* gutils.c:
Conditionalized inclusion of platform-dependent headers. Use
the platform-independent file name syntax macros.
Conditionalize code on platform-dependent features. Added the
functions g_path_is_absolute g_path_skip_root and g_getenv.
Added the GIOChannel-related functions. Added
compiler-dependent Unix compatibility functions for Windows.
* makefile.lcc makefile.msc:
New files. Compiler-specific makefiles for LCC-Win32 and
Microsoft C. Only Microsoft C is actually supported currently.
* testglib.c:
Added pathname check cases for Windows. Added workaround for
bug in the Microsoft runtime library. Improved some tests a bit.
Tue Oct 27 04:00:11 1998 Tim Janik <timj@gtk.org>
* testgmodule.c (main): changed the #ifdef WIN32 test to NATIVE_WIN32,
this needs to be more constistent throughout the code, do we go for
NATIVE_WIN32 or WIN32?
* gmodule.c (LibMain): special cased the #ifdef __LCC__ case for
NATIVE_WIN32, since lcc maybe used on other platforms as well.
* libgplugin_a.c (LibMain):
* libgplugin_b.c (LibMain):
likewise. not sure i like this special requirement for lcc in here.
* gmodule-dl.c (_g_module_build_path):
feature empty "" directories and prepend the module name with "lib".
* gmodule-dld.c (_g_module_build_path):
* gmodule-win32.c (_g_module_build_path):
feature empty "" directories.
* we need some more magic in the _g_module_build_path variants
so we don't append/prepend lib and .so, .sl or .dll for those names
that already contain it.
* applied patch from Tor Lillqvist for g_module_build_path() and
windows support.
1998-10-20: Tor Lillqvist <tml@iki.fi>
* gmodule/gmodule-win32.c:
New file.
* gmodule/gmodule.c gmodule/gmodule.h:
Added the funcion g_module_build_path that builds the path to
a module file, decorating the name according to the system's
conventions. Added the Windows implementation.
* gmodule/libgplugin_a.c gmodule/libgplugin_b.c:
Added LibMain for LCC-Win32.
* gmodule/testgmodule.c:
Handle Windows dll names.
1998-10-27 05:11:34 +01:00
|
|
|
#endif
|
2005-08-17 20:31:08 +02:00
|
|
|
#ifdef HAVE_CRT_EXTERNS_H
|
2005-08-24 05:11:45 +02:00
|
|
|
#include <crt_externs.h> /* for _NSGetEnviron */
|
2005-08-17 20:31:08 +02:00
|
|
|
#endif
|
removed dummy structure definitions for struct _GCache, _GTree, _GTimer,
Tue Oct 27 03:00:50 1998 Tim Janik <timj@gtk.org>
* glib.h: removed dummy structure definitions for struct _GCache,
_GTree, _GTimer, _GMemChunk, _GListAllocator and _GStringChunk.
* gutils.c: implement glib's inline functions _after_ all include
statements have been processed.
removed Tor's MAXPATHLEN check since there already was one supplied
further down in this file.
(LibMain): special cased the #ifdef __LCC__ case for NATIVE_WIN32,
since lcc maybe used on other platforms as well. why in hell is this
stuff required?
(g_get_any_init): for windows, if the user name is supplied, use it as
realname also.
in general, if there is no homedir specified, use the tmpdir that
we already figured.
* gtimer.c (g_timer_elapsed): changed a g_assert() statement to
g_return_if_fail().
* applied glib-tml-981020-0.patch for WIN32 portability, added some
comments and g_return_if_fail() statements, minor indentation fixes.
ChangeLog entry from Tor Lillqvist is appended.
* glib.h (struct dirent): use lower case structure members.
* glib.h:
* makefile.lcc:
* makefile.msc:
s/COMPILING_GLIB/GLIB_COMPILATION/
1998-10-20: Tor Lillqvist <tml@iki.fi>
* README.win32 glib.def gmodule.def
* glibconfig.h.win32 gmodule/gmoduleconf.h.win32:
New files for the Windows port. The .def files list exported
symbols for the Microsoft linker and compatibles.
* configure.in:
Added checks for some platform-dependent headers: pwd.h sys/param.h
sys/select.h sys/time.h sys/times.h unistd.h, and the function lstat.
* gerror.c:
Conditionalized inclusion of system-dependent headers. Changes
for Windows: no gdb to do a stack trace. Just call abort().
* glib.h:
Changes for Windows:
Added macros G_DIR_SEPARATOR, G_DIR_SEPARATOR_S for
platform-dependent file name syntax elements. Added macros
G_SEARCHPATH_SEPARATOR, G_SEARCHPATH_SEPARATOR_S for
platform-dependent search path syntax conventions.
Added pragmas for Microsoft C to make it more pedantic.
Marked GLib's global variables for export from DLL.
Added the function g_strescape that escapes backslashes.
Added functions g_path_is_absolute and g_path_skip_root to
handle platform-dependent file name syntax.
Added the function g_getenv that expands environment variables
that contain references to other environment variables, as is
typical on Windows NT.
Added the GIOChannel structure which is used to encapsulate the
IPC mechanism used by the GIMP's plug-ins, and possibly other
things later. On Unix a GIOChannel encapsulates just a file
descriptor. On Windows it contains a file handle from _pipe() and a
few other things related to the implementation of gdk_input_add
and GIMP plug-in communication. Subject to change.
Removed duplicate declarations of the version variables.
For the Microsoft compiler, declare own implementation of
ftruncate and the <dirent.h> functions.
* gmem.c:
Define a symbolic name for the profiling table size.
* gmessages.c:
Conditionalized inclusion of unistd.h. On Windows, output using
stdio to stdout.
* gscanner.c:
Conditionalized inclusion of unistd.h. Added changes for
Microsoft C. Added CR to the skipped character set. Added small
workaround for MSC compiler bug in g_scanner_cur_value.
* gstrfuncs.c:
Added the function g_strescape, which escapes the backslash
character. Needed especially when printing Windows filenames.
* gtimer.c:
Conditionalized inclusion of unistd.h and sys/time.h. Added
implementations for Windows.
* gutils.c:
Conditionalized inclusion of platform-dependent headers. Use
the platform-independent file name syntax macros.
Conditionalize code on platform-dependent features. Added the
functions g_path_is_absolute g_path_skip_root and g_getenv.
Added the GIOChannel-related functions. Added
compiler-dependent Unix compatibility functions for Windows.
* makefile.lcc makefile.msc:
New files. Compiler-specific makefiles for LCC-Win32 and
Microsoft C. Only Microsoft C is actually supported currently.
* testglib.c:
Added pathname check cases for Windows. Added workaround for
bug in the Microsoft runtime library. Improved some tests a bit.
Tue Oct 27 04:00:11 1998 Tim Janik <timj@gtk.org>
* testgmodule.c (main): changed the #ifdef WIN32 test to NATIVE_WIN32,
this needs to be more constistent throughout the code, do we go for
NATIVE_WIN32 or WIN32?
* gmodule.c (LibMain): special cased the #ifdef __LCC__ case for
NATIVE_WIN32, since lcc maybe used on other platforms as well.
* libgplugin_a.c (LibMain):
* libgplugin_b.c (LibMain):
likewise. not sure i like this special requirement for lcc in here.
* gmodule-dl.c (_g_module_build_path):
feature empty "" directories and prepend the module name with "lib".
* gmodule-dld.c (_g_module_build_path):
* gmodule-win32.c (_g_module_build_path):
feature empty "" directories.
* we need some more magic in the _g_module_build_path variants
so we don't append/prepend lib and .so, .sl or .dll for those names
that already contain it.
* applied patch from Tor Lillqvist for g_module_build_path() and
windows support.
1998-10-20: Tor Lillqvist <tml@iki.fi>
* gmodule/gmodule-win32.c:
New file.
* gmodule/gmodule.c gmodule/gmodule.h:
Added the funcion g_module_build_path that builds the path to
a module file, decorating the name according to the system's
conventions. Added the Windows implementation.
* gmodule/libgplugin_a.c gmodule/libgplugin_b.c:
Added LibMain for LCC-Win32.
* gmodule/testgmodule.c:
Handle Windows dll names.
1998-10-27 05:11:34 +01:00
|
|
|
|
2011-10-04 21:44:48 +02:00
|
|
|
#include "glib-init.h"
|
2012-11-02 00:37:57 +01:00
|
|
|
#include "glib-private.h"
|
2011-10-15 22:13:08 +02:00
|
|
|
#include "genviron.h"
|
2010-09-05 06:23:03 +02:00
|
|
|
#include "gfileutils.h"
|
2011-10-17 07:52:10 +02:00
|
|
|
#include "ggettext.h"
|
2010-09-05 06:23:03 +02:00
|
|
|
#include "ghash.h"
|
|
|
|
#include "gthread.h"
|
|
|
|
#include "gtestutils.h"
|
|
|
|
#include "gunicode.h"
|
|
|
|
#include "gstrfuncs.h"
|
2010-03-01 16:32:09 +01:00
|
|
|
#include "garray.h"
|
2007-11-28 15:35:14 +01:00
|
|
|
#include "glibintl.h"
|
1998-06-11 01:21:14 +02:00
|
|
|
|
2010-09-06 14:56:16 +02:00
|
|
|
#ifdef G_PLATFORM_WIN32
|
|
|
|
#include "gconvert.h"
|
|
|
|
#include "gwin32.h"
|
|
|
|
#endif
|
|
|
|
|
2011-06-09 05:44:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:misc_utils
|
|
|
|
* @title: Miscellaneous Utility Functions
|
|
|
|
* @short_description: a selection of portable utility functions
|
|
|
|
*
|
|
|
|
* These are portable utility functions.
|
|
|
|
*/
|
|
|
|
|
2001-03-09 22:31:21 +01:00
|
|
|
#ifdef G_PLATFORM_WIN32
|
2000-03-22 21:46:19 +01:00
|
|
|
# include <windows.h>
|
2005-04-08 14:03:16 +02:00
|
|
|
# ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
|
|
|
# define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2
|
|
|
|
# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4
|
|
|
|
# endif
|
2001-12-31 11:12:22 +01:00
|
|
|
# include <lmcons.h> /* For UNLEN */
|
2001-03-09 22:31:21 +01:00
|
|
|
#endif /* G_PLATFORM_WIN32 */
|
|
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
2000-03-22 21:46:19 +01:00
|
|
|
# include <direct.h>
|
2004-08-25 02:39:13 +02:00
|
|
|
# include <shlobj.h>
|
2004-10-29 22:58:04 +02:00
|
|
|
/* older SDK (e.g. msvc 5.0) does not have these*/
|
2007-06-06 21:13:45 +02:00
|
|
|
# ifndef CSIDL_MYMUSIC
|
|
|
|
# define CSIDL_MYMUSIC 13
|
|
|
|
# endif
|
|
|
|
# ifndef CSIDL_MYVIDEO
|
|
|
|
# define CSIDL_MYVIDEO 14
|
|
|
|
# endif
|
2004-10-29 22:58:04 +02:00
|
|
|
# ifndef CSIDL_INTERNET_CACHE
|
|
|
|
# define CSIDL_INTERNET_CACHE 32
|
|
|
|
# endif
|
|
|
|
# ifndef CSIDL_COMMON_APPDATA
|
|
|
|
# define CSIDL_COMMON_APPDATA 35
|
|
|
|
# endif
|
2008-02-17 13:49:12 +01:00
|
|
|
# ifndef CSIDL_MYPICTURES
|
|
|
|
# define CSIDL_MYPICTURES 0x27
|
|
|
|
# endif
|
2004-10-29 22:58:04 +02:00
|
|
|
# ifndef CSIDL_COMMON_DOCUMENTS
|
|
|
|
# define CSIDL_COMMON_DOCUMENTS 46
|
|
|
|
# endif
|
|
|
|
# ifndef CSIDL_PROFILE
|
|
|
|
# define CSIDL_PROFILE 40
|
|
|
|
# endif
|
2005-04-09 03:21:29 +02:00
|
|
|
# include <process.h>
|
2001-03-09 22:31:21 +01:00
|
|
|
#endif
|
2000-03-22 21:46:19 +01:00
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
#ifdef HAVE_CARBON
|
|
|
|
#include <CoreServices/CoreServices.h>
|
|
|
|
#endif
|
|
|
|
|
2000-05-29 20:48:29 +02:00
|
|
|
#ifdef HAVE_CODESET
|
|
|
|
#include <langinfo.h>
|
|
|
|
#endif
|
|
|
|
|
2005-04-08 02:40:02 +02:00
|
|
|
#ifdef G_PLATFORM_WIN32
|
|
|
|
|
2008-02-24 22:15:47 +01:00
|
|
|
gchar *
|
2008-09-19 12:20:41 +02:00
|
|
|
_glib_get_dll_directory (void)
|
2008-02-24 22:15:47 +01:00
|
|
|
{
|
2008-09-19 12:20:41 +02:00
|
|
|
gchar *retval;
|
|
|
|
gchar *p;
|
|
|
|
wchar_t wc_fn[MAX_PATH];
|
|
|
|
|
2008-04-03 22:17:15 +02:00
|
|
|
#ifdef DLL_EXPORT
|
2008-02-24 22:15:47 +01:00
|
|
|
if (glib_dll == NULL)
|
|
|
|
return NULL;
|
2008-04-03 22:17:15 +02:00
|
|
|
#endif
|
2008-09-19 12:20:41 +02:00
|
|
|
|
|
|
|
/* This code is different from that in
|
|
|
|
* g_win32_get_package_installation_directory_of_module() in that
|
|
|
|
* here we return the actual folder where the GLib DLL is. We don't
|
|
|
|
* do the check for it being in a "bin" or "lib" subfolder and then
|
|
|
|
* returning the parent of that.
|
|
|
|
*
|
|
|
|
* In a statically built GLib, glib_dll will be NULL and we will
|
|
|
|
* thus look up the application's .exe file's location.
|
2008-04-03 22:17:15 +02:00
|
|
|
*/
|
2008-09-19 12:20:41 +02:00
|
|
|
if (!GetModuleFileNameW (glib_dll, wc_fn, MAX_PATH))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
p = strrchr (retval, G_DIR_SEPARATOR);
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
/* Wtf? */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
return retval;
|
2008-02-24 22:15:47 +01:00
|
|
|
}
|
|
|
|
|
2005-04-08 02:40:02 +02:00
|
|
|
#endif
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_memmove:
|
|
|
|
* @dest: the destination address to copy the bytes to.
|
|
|
|
* @src: the source address to copy the bytes from.
|
|
|
|
* @len: the number of bytes to copy.
|
|
|
|
*
|
|
|
|
* Copies a block of memory @len bytes long, from @src to @dest.
|
|
|
|
* The source and destination areas may overlap.
|
|
|
|
*
|
Require C90 compliance
Assume all supported platforms implement C90, and therefore they
(correctly) implement atexit(), memmove(), setlocale(), strerror(),
and vprintf(), and have <float.h> and <limits.h>.
(Also remove the configure check testing that "do ... while (0)" works
correctly; the non-do/while-based version of G_STMT_START and
G_STMT_END was removed years ago, but the check remained. Also, remove
some checks that configure.ac claimed were needed for libcharset, but
aren't actually used.)
Note that removing the g_memmove() function is not an ABI break even
on systems where g_memmove() was previously not a macro, because it
was never marked GLIB_AVAILABLE_IN_ALL or listed in glib.symbols, so
it would have been glib-internal since 2004.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:58 +02:00
|
|
|
* Deprecated:2.40: Just use memmove().
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
1999-07-01 11:30:18 +02:00
|
|
|
|
2005-08-31 23:02:47 +02:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
#undef g_atexit
|
|
|
|
#endif
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_atexit:
|
2011-04-03 18:53:04 +02:00
|
|
|
* @func: (scope async): the function to call on normal program termination.
|
2005-02-02 07:07:14 +01:00
|
|
|
*
|
|
|
|
* Specifies a function to be called at normal program termination.
|
2005-08-31 23:02:47 +02:00
|
|
|
*
|
|
|
|
* Since GLib 2.8.2, on Windows g_atexit() actually is a preprocessor
|
|
|
|
* macro that maps to a call to the atexit() function in the C
|
|
|
|
* library. This means that in case the code that calls g_atexit(),
|
|
|
|
* i.e. atexit(), is in a DLL, the function will be called when the
|
|
|
|
* DLL is detached from the program. This typically makes more sense
|
|
|
|
* than that the function is called when the GLib DLL is detached,
|
|
|
|
* which happened earlier when g_atexit() was a function in the GLib
|
|
|
|
* DLL.
|
|
|
|
*
|
|
|
|
* The behaviour of atexit() in the context of dynamically loaded
|
|
|
|
* modules is not formally specified and varies wildly.
|
|
|
|
*
|
|
|
|
* On POSIX systems, calling g_atexit() (or atexit()) in a dynamically
|
|
|
|
* loaded module which is unloaded before the program terminates might
|
|
|
|
* well cause a crash at program exit.
|
|
|
|
*
|
|
|
|
* Some POSIX systems implement atexit() like Windows, and have each
|
|
|
|
* dynamically loaded module maintain an own atexit chain that is
|
|
|
|
* called when the module is unloaded.
|
|
|
|
*
|
|
|
|
* On other POSIX systems, before a dynamically loaded module is
|
|
|
|
* unloaded, the registered atexit functions (if any) residing in that
|
|
|
|
* module are called, regardless where the code that registered them
|
|
|
|
* resided. This is presumably the most robust approach.
|
|
|
|
*
|
|
|
|
* As can be seen from the above, for portability it's best to avoid
|
|
|
|
* calling g_atexit() (or atexit()) except in the main executable of a
|
|
|
|
* program.
|
2011-10-20 03:03:43 +02:00
|
|
|
*
|
2011-12-24 15:31:55 +01:00
|
|
|
* Deprecated:2.32: It is best to avoid g_atexit().
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
1998-09-08 06:00:13 +02:00
|
|
|
void
|
|
|
|
g_atexit (GVoidFunc func)
|
|
|
|
{
|
|
|
|
gint result;
|
|
|
|
|
|
|
|
result = atexit ((void (*)(void)) func);
|
|
|
|
if (result)
|
Require C90 compliance
Assume all supported platforms implement C90, and therefore they
(correctly) implement atexit(), memmove(), setlocale(), strerror(),
and vprintf(), and have <float.h> and <limits.h>.
(Also remove the configure check testing that "do ... while (0)" works
correctly; the non-do/while-based version of G_STMT_START and
G_STMT_END was removed years ago, but the check remained. Also, remove
some checks that configure.ac claimed were needed for libcharset, but
aren't actually used.)
Note that removing the g_memmove() function is not an ABI break even
on systems where g_memmove() was previously not a macro, because it
was never marked GLIB_AVAILABLE_IN_ALL or listed in glib.symbols, so
it would have been glib-internal since 2004.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:58 +02:00
|
|
|
{
|
|
|
|
g_error ("Could not register atexit() function: %s",
|
|
|
|
g_strerror (errno));
|
|
|
|
}
|
1998-09-08 06:00:13 +02:00
|
|
|
}
|
|
|
|
|
2000-10-09 18:24:57 +02:00
|
|
|
/* Based on execvp() from GNU Libc.
|
|
|
|
* Some of this code is cut-and-pasted into gspawn.c
|
|
|
|
*/
|
|
|
|
|
|
|
|
static gchar*
|
2005-02-02 07:07:14 +01:00
|
|
|
my_strchrnul (const gchar *str,
|
|
|
|
gchar c)
|
2000-10-09 18:24:57 +02:00
|
|
|
{
|
|
|
|
gchar *p = (gchar*)str;
|
|
|
|
while (*p && (*p != c))
|
|
|
|
++p;
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2001-03-01 11:25:12 +01:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
2003-10-24 05:41:22 +02:00
|
|
|
static gchar *inner_find_program_in_path (const gchar *program);
|
2001-03-01 11:25:12 +01:00
|
|
|
|
|
|
|
gchar*
|
|
|
|
g_find_program_in_path (const gchar *program)
|
|
|
|
{
|
|
|
|
const gchar *last_dot = strrchr (program, '.');
|
|
|
|
|
2005-01-01 03:09:51 +01:00
|
|
|
if (last_dot == NULL ||
|
|
|
|
strchr (last_dot, '\\') != NULL ||
|
|
|
|
strchr (last_dot, '/') != NULL)
|
2001-03-01 11:25:12 +01:00
|
|
|
{
|
|
|
|
const gint program_length = strlen (program);
|
2005-01-01 03:09:51 +01:00
|
|
|
gchar *pathext = g_build_path (";",
|
|
|
|
".exe;.cmd;.bat;.com",
|
|
|
|
g_getenv ("PATHEXT"),
|
|
|
|
NULL);
|
|
|
|
gchar *p;
|
2001-03-01 11:25:12 +01:00
|
|
|
gchar *decorated_program;
|
|
|
|
gchar *retval;
|
|
|
|
|
|
|
|
p = pathext;
|
|
|
|
do
|
|
|
|
{
|
2005-01-01 03:09:51 +01:00
|
|
|
gchar *q = my_strchrnul (p, ';');
|
2001-03-01 11:25:12 +01:00
|
|
|
|
2005-01-01 03:09:51 +01:00
|
|
|
decorated_program = g_malloc (program_length + (q-p) + 1);
|
2001-03-01 11:25:12 +01:00
|
|
|
memcpy (decorated_program, program, program_length);
|
2005-01-01 03:09:51 +01:00
|
|
|
memcpy (decorated_program+program_length, p, q-p);
|
|
|
|
decorated_program [program_length + (q-p)] = '\0';
|
2001-03-01 11:25:12 +01:00
|
|
|
|
|
|
|
retval = inner_find_program_in_path (decorated_program);
|
|
|
|
g_free (decorated_program);
|
|
|
|
|
|
|
|
if (retval != NULL)
|
2005-01-01 03:09:51 +01:00
|
|
|
{
|
|
|
|
g_free (pathext);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
p = q;
|
2001-03-01 11:25:12 +01:00
|
|
|
} while (*p++ != '\0');
|
2005-01-01 03:09:51 +01:00
|
|
|
g_free (pathext);
|
2001-03-01 11:25:12 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return inner_find_program_in_path (program);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2000-10-09 18:24:57 +02:00
|
|
|
/**
|
|
|
|
* g_find_program_in_path:
|
2016-06-04 15:46:12 +02:00
|
|
|
* @program: (type filename): a program name in the GLib file name encoding
|
2000-10-09 18:24:57 +02:00
|
|
|
*
|
2000-11-05 17:38:16 +01:00
|
|
|
* Locates the first executable named @program in the user's path, in the
|
2000-10-09 18:24:57 +02:00
|
|
|
* same way that execvp() would locate it. Returns an allocated string
|
2005-01-03 20:57:20 +01:00
|
|
|
* with the absolute path name, or %NULL if the program is not found in
|
2000-11-05 17:38:16 +01:00
|
|
|
* the path. If @program is already an absolute path, returns a copy of
|
2005-01-03 20:57:20 +01:00
|
|
|
* @program if @program exists and is executable, and %NULL otherwise.
|
|
|
|
*
|
2005-01-01 03:09:51 +01:00
|
|
|
* On Windows, if @program does not have a file type suffix, tries
|
|
|
|
* with the suffixes .exe, .cmd, .bat and .com, and the suffixes in
|
2014-02-06 01:32:41 +01:00
|
|
|
* the `PATHEXT` environment variable.
|
2005-03-07 14:49:24 +01:00
|
|
|
*
|
|
|
|
* On Windows, it looks for the file in the same way as CreateProcess()
|
2005-01-01 03:09:51 +01:00
|
|
|
* would. This means first in the directory where the executing
|
2001-03-01 11:25:12 +01:00
|
|
|
* program was loaded from, then in the current directory, then in the
|
|
|
|
* Windows 32-bit system directory, then in the Windows directory, and
|
2014-02-06 01:32:41 +01:00
|
|
|
* finally in the directories in the `PATH` environment variable. If
|
|
|
|
* the program is found, the return value contains the full name
|
|
|
|
* including the type suffix.
|
2001-03-01 11:25:12 +01:00
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): a newly-allocated string with the absolute path,
|
|
|
|
* or %NULL
|
2000-10-09 18:24:57 +02:00
|
|
|
**/
|
2003-10-24 05:41:22 +02:00
|
|
|
#ifdef G_OS_WIN32
|
2005-01-01 03:09:51 +01:00
|
|
|
static gchar *
|
|
|
|
inner_find_program_in_path (const gchar *program)
|
|
|
|
#else
|
2000-10-09 18:24:57 +02:00
|
|
|
gchar*
|
2000-11-05 17:38:16 +01:00
|
|
|
g_find_program_in_path (const gchar *program)
|
2005-01-01 03:09:51 +01:00
|
|
|
#endif
|
2000-10-09 18:24:57 +02:00
|
|
|
{
|
2001-02-18 00:30:48 +01:00
|
|
|
const gchar *path, *p;
|
|
|
|
gchar *name, *freeme;
|
2001-03-01 10:34:45 +01:00
|
|
|
#ifdef G_OS_WIN32
|
2005-01-01 03:09:51 +01:00
|
|
|
const gchar *path_copy;
|
|
|
|
gchar *filename = NULL, *appdir = NULL;
|
|
|
|
gchar *sysdir = NULL, *windir = NULL;
|
2006-08-30 00:45:00 +02:00
|
|
|
int n;
|
|
|
|
wchar_t wfilename[MAXPATHLEN], wsysdir[MAXPATHLEN],
|
|
|
|
wwindir[MAXPATHLEN];
|
2001-03-01 10:34:45 +01:00
|
|
|
#endif
|
2006-12-28 05:48:06 +01:00
|
|
|
gsize len;
|
|
|
|
gsize pathlen;
|
2000-10-09 18:24:57 +02:00
|
|
|
|
2000-11-05 17:38:16 +01:00
|
|
|
g_return_val_if_fail (program != NULL, NULL);
|
2000-10-09 18:24:57 +02:00
|
|
|
|
2001-03-01 11:25:12 +01:00
|
|
|
/* If it is an absolute path, or a relative path including subdirectories,
|
|
|
|
* don't look in PATH.
|
|
|
|
*/
|
|
|
|
if (g_path_is_absolute (program)
|
2003-08-16 21:45:25 +02:00
|
|
|
|| strchr (program, G_DIR_SEPARATOR) != NULL
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|| strchr (program, '/') != NULL
|
|
|
|
#endif
|
|
|
|
)
|
2000-10-09 18:24:57 +02:00
|
|
|
{
|
2005-01-03 20:57:20 +01:00
|
|
|
if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE) &&
|
|
|
|
!g_file_test (program, G_FILE_TEST_IS_DIR))
|
2000-11-05 17:38:16 +01:00
|
|
|
return g_strdup (program);
|
2000-10-09 18:24:57 +02:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = g_getenv ("PATH");
|
Remove alleged support for BeOS
Since the initial addition of BeOS support in 1999, there has only
been one update to it (in 2005, and it wasn't even very big). GLib is
known to not currently build on Haiku (or presumably actual BeOS)
without additional patching, and the fact that there isn't a single
G_OS_BEOS check in gio/ is suspicious.
Additionally, other than the GModule implementation, all of the
existing G_OS_BEOS checks are either (a) "G_OS_UNIX || G_OS_BEOS", or
(b) random minor POSIXy tweaks (include this header file rather than
that one, etc), suggesting that if we were going to support Haiku, it
would probably be simpler to treat it as a special kind of G_OS_UNIX
(as we do with Mac OS X) rather than as its own completely different
thing.
So, kill G_OS_BEOS.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:55 +02:00
|
|
|
#if defined(G_OS_UNIX)
|
2000-10-09 18:24:57 +02:00
|
|
|
if (path == NULL)
|
|
|
|
{
|
2013-05-20 22:54:48 +02:00
|
|
|
/* There is no 'PATH' in the environment. The default
|
2000-11-05 17:38:16 +01:00
|
|
|
* search path in GNU libc is the current directory followed by
|
2013-05-20 22:54:48 +02:00
|
|
|
* the path 'confstr' returns for '_CS_PATH'.
|
2000-10-09 18:24:57 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* In GLib we put . last, for security, and don't use the
|
|
|
|
* unportable confstr(); UNIX98 does not actually specify
|
|
|
|
* what to search if PATH is unset. POSIX may, dunno.
|
|
|
|
*/
|
|
|
|
|
|
|
|
path = "/bin:/usr/bin:.";
|
|
|
|
}
|
2001-03-01 10:34:45 +01:00
|
|
|
#else
|
2006-08-30 00:45:00 +02:00
|
|
|
n = GetModuleFileNameW (NULL, wfilename, MAXPATHLEN);
|
|
|
|
if (n > 0 && n < MAXPATHLEN)
|
|
|
|
filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
n = GetSystemDirectoryW (wsysdir, MAXPATHLEN);
|
|
|
|
if (n > 0 && n < MAXPATHLEN)
|
|
|
|
sysdir = g_utf16_to_utf8 (wsysdir, -1, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
n = GetWindowsDirectoryW (wwindir, MAXPATHLEN);
|
|
|
|
if (n > 0 && n < MAXPATHLEN)
|
|
|
|
windir = g_utf16_to_utf8 (wwindir, -1, NULL, NULL, NULL);
|
2005-01-01 03:09:51 +01:00
|
|
|
|
|
|
|
if (filename)
|
|
|
|
{
|
|
|
|
appdir = g_path_get_dirname (filename);
|
|
|
|
g_free (filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
path = g_strdup (path);
|
|
|
|
|
|
|
|
if (windir)
|
|
|
|
{
|
|
|
|
const gchar *tem = path;
|
|
|
|
path = g_strconcat (windir, ";", path, NULL);
|
|
|
|
g_free ((gchar *) tem);
|
|
|
|
g_free (windir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sysdir)
|
|
|
|
{
|
|
|
|
const gchar *tem = path;
|
|
|
|
path = g_strconcat (sysdir, ";", path, NULL);
|
|
|
|
g_free ((gchar *) tem);
|
|
|
|
g_free (sysdir);
|
|
|
|
}
|
|
|
|
|
2001-03-01 10:34:45 +01:00
|
|
|
{
|
2005-01-01 03:09:51 +01:00
|
|
|
const gchar *tem = path;
|
|
|
|
path = g_strconcat (".;", path, NULL);
|
|
|
|
g_free ((gchar *) tem);
|
2001-03-01 10:34:45 +01:00
|
|
|
}
|
2005-01-01 03:09:51 +01:00
|
|
|
|
|
|
|
if (appdir)
|
|
|
|
{
|
|
|
|
const gchar *tem = path;
|
|
|
|
path = g_strconcat (appdir, ";", path, NULL);
|
|
|
|
g_free ((gchar *) tem);
|
|
|
|
g_free (appdir);
|
|
|
|
}
|
|
|
|
|
|
|
|
path_copy = path;
|
2001-03-01 10:34:45 +01:00
|
|
|
#endif
|
2000-10-09 18:24:57 +02:00
|
|
|
|
2000-11-05 17:38:16 +01:00
|
|
|
len = strlen (program) + 1;
|
2000-10-09 18:24:57 +02:00
|
|
|
pathlen = strlen (path);
|
|
|
|
freeme = name = g_malloc (pathlen + len + 1);
|
|
|
|
|
|
|
|
/* Copy the file name at the top, including '\0' */
|
2000-11-05 17:38:16 +01:00
|
|
|
memcpy (name + pathlen + 1, program, len);
|
2000-10-09 18:24:57 +02:00
|
|
|
name = name + pathlen;
|
|
|
|
/* And add the slash before the filename */
|
2001-03-01 10:34:45 +01:00
|
|
|
*name = G_DIR_SEPARATOR;
|
2000-10-09 18:24:57 +02:00
|
|
|
|
|
|
|
p = path;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
char *startp;
|
|
|
|
|
|
|
|
path = p;
|
2001-03-01 10:34:45 +01:00
|
|
|
p = my_strchrnul (path, G_SEARCHPATH_SEPARATOR);
|
2000-10-09 18:24:57 +02:00
|
|
|
|
|
|
|
if (p == path)
|
|
|
|
/* Two adjacent colons, or a colon at the beginning or the end
|
2013-05-20 22:54:48 +02:00
|
|
|
* of 'PATH' means to search the current directory.
|
2000-10-09 18:24:57 +02:00
|
|
|
*/
|
|
|
|
startp = name + 1;
|
|
|
|
else
|
|
|
|
startp = memcpy (name - (p - path), path, p - path);
|
|
|
|
|
2005-01-03 20:57:20 +01:00
|
|
|
if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE) &&
|
|
|
|
!g_file_test (startp, G_FILE_TEST_IS_DIR))
|
2000-10-09 18:24:57 +02:00
|
|
|
{
|
|
|
|
gchar *ret;
|
|
|
|
ret = g_strdup (startp);
|
|
|
|
g_free (freeme);
|
2001-03-01 10:34:45 +01:00
|
|
|
#ifdef G_OS_WIN32
|
2005-01-01 03:09:51 +01:00
|
|
|
g_free ((gchar *) path_copy);
|
2001-03-01 10:34:45 +01:00
|
|
|
#endif
|
2000-10-09 18:24:57 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (*p++ != '\0');
|
|
|
|
|
|
|
|
g_free (freeme);
|
2001-03-01 10:34:45 +01:00
|
|
|
#ifdef G_OS_WIN32
|
2005-01-01 03:09:51 +01:00
|
|
|
g_free ((gchar *) path_copy);
|
2001-03-01 10:34:45 +01:00
|
|
|
#endif
|
2000-10-09 18:24:57 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-11-09 17:12:18 +01:00
|
|
|
/* The functions below are defined this way for compatibility reasons.
|
|
|
|
* See the note in gutils.h.
|
|
|
|
*/
|
|
|
|
|
2011-06-09 05:44:39 +02:00
|
|
|
/**
|
|
|
|
* g_bit_nth_lsf:
|
|
|
|
* @mask: a #gulong containing flags
|
|
|
|
* @nth_bit: the index of the bit to start the search from
|
|
|
|
*
|
|
|
|
* Find the position of the first bit set in @mask, searching
|
|
|
|
* from (but not including) @nth_bit upwards. Bits are numbered
|
|
|
|
* from 0 (least significant) to sizeof(#gulong) * 8 - 1 (31 or 63,
|
|
|
|
* usually). To start searching from the 0th bit, set @nth_bit to -1.
|
|
|
|
*
|
2015-08-25 11:49:06 +02:00
|
|
|
* Returns: the index of the first bit set which is higher than @nth_bit, or -1
|
|
|
|
* if no higher bits are set
|
2011-06-09 05:44:39 +02:00
|
|
|
*/
|
2015-11-09 17:12:18 +01:00
|
|
|
gint
|
|
|
|
(g_bit_nth_lsf) (gulong mask,
|
|
|
|
gint nth_bit)
|
|
|
|
{
|
|
|
|
return g_bit_nth_lsf_impl (mask, nth_bit);
|
|
|
|
}
|
2011-06-09 05:44:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* g_bit_nth_msf:
|
|
|
|
* @mask: a #gulong containing flags
|
|
|
|
* @nth_bit: the index of the bit to start the search from
|
|
|
|
*
|
|
|
|
* Find the position of the first bit set in @mask, searching
|
|
|
|
* from (but not including) @nth_bit downwards. Bits are numbered
|
|
|
|
* from 0 (least significant) to sizeof(#gulong) * 8 - 1 (31 or 63,
|
|
|
|
* usually). To start searching from the last bit, set @nth_bit to
|
|
|
|
* -1 or GLIB_SIZEOF_LONG * 8.
|
|
|
|
*
|
2015-08-25 11:49:06 +02:00
|
|
|
* Returns: the index of the first bit set which is lower than @nth_bit, or -1
|
|
|
|
* if no lower bits are set
|
2011-06-09 05:44:39 +02:00
|
|
|
*/
|
2015-11-09 17:12:18 +01:00
|
|
|
gint
|
|
|
|
(g_bit_nth_msf) (gulong mask,
|
|
|
|
gint nth_bit)
|
|
|
|
{
|
|
|
|
return g_bit_nth_msf_impl (mask, nth_bit);
|
|
|
|
}
|
|
|
|
|
2011-06-09 05:44:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* g_bit_storage:
|
|
|
|
* @number: a #guint
|
|
|
|
*
|
|
|
|
* Gets the number of bits used to hold @number,
|
|
|
|
* e.g. if @number is 4, 3 bits are needed.
|
|
|
|
*
|
|
|
|
* Returns: the number of bits used to hold @number
|
|
|
|
*/
|
2015-11-09 17:12:18 +01:00
|
|
|
guint
|
|
|
|
(g_bit_storage) (gulong number)
|
|
|
|
{
|
|
|
|
return g_bit_storage_impl (number);
|
|
|
|
}
|
2011-06-09 05:44:39 +02:00
|
|
|
|
1999-02-10 10:40:46 +01:00
|
|
|
G_LOCK_DEFINE_STATIC (g_utils_global);
|
1998-12-15 06:28:02 +01:00
|
|
|
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gchar *user_name;
|
|
|
|
gchar *real_name;
|
|
|
|
gchar *home_dir;
|
|
|
|
} UserDatabaseEntry;
|
1998-07-10 07:51:17 +02:00
|
|
|
|
2004-08-11 19:53:05 +02:00
|
|
|
static gchar *g_user_data_dir = NULL;
|
|
|
|
static gchar **g_system_data_dirs = NULL;
|
|
|
|
static gchar *g_user_cache_dir = NULL;
|
|
|
|
static gchar *g_user_config_dir = NULL;
|
|
|
|
static gchar **g_system_config_dirs = NULL;
|
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
static gchar **g_user_special_dirs = NULL;
|
|
|
|
|
|
|
|
/* fifteen minutes of fame for everybody */
|
|
|
|
#define G_USER_DIRS_EXPIRE 15 * 60
|
|
|
|
|
2004-08-25 02:39:13 +02:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
get_special_folder (int csidl)
|
|
|
|
{
|
2007-08-01 11:49:02 +02:00
|
|
|
wchar_t path[MAX_PATH+1];
|
2004-08-25 02:39:13 +02:00
|
|
|
HRESULT hr;
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
BOOL b;
|
|
|
|
gchar *retval = NULL;
|
|
|
|
|
|
|
|
hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl);
|
|
|
|
if (hr == S_OK)
|
|
|
|
{
|
2007-08-01 11:49:02 +02:00
|
|
|
b = SHGetPathFromIDListW (pidl, path);
|
2006-08-30 00:45:00 +02:00
|
|
|
if (b)
|
2007-08-01 11:49:02 +02:00
|
|
|
retval = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL);
|
2004-08-25 02:39:13 +02:00
|
|
|
CoTaskMemFree (pidl);
|
|
|
|
}
|
2004-10-29 22:58:04 +02:00
|
|
|
return retval;
|
2004-08-25 02:39:13 +02:00
|
|
|
}
|
|
|
|
|
2005-06-08 22:03:12 +02:00
|
|
|
static char *
|
|
|
|
get_windows_directory_root (void)
|
|
|
|
{
|
2006-12-28 16:47:42 +01:00
|
|
|
wchar_t wwindowsdir[MAX_PATH];
|
2005-06-08 22:03:12 +02:00
|
|
|
|
2006-12-28 16:47:42 +01:00
|
|
|
if (GetWindowsDirectoryW (wwindowsdir, G_N_ELEMENTS (wwindowsdir)))
|
2005-06-08 22:03:12 +02:00
|
|
|
{
|
|
|
|
/* Usually X:\Windows, but in terminal server environments
|
|
|
|
* might be an UNC path, AFAIK.
|
|
|
|
*/
|
2006-12-28 16:47:42 +01:00
|
|
|
char *windowsdir = g_utf16_to_utf8 (wwindowsdir, -1, NULL, NULL, NULL);
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (windowsdir == NULL)
|
|
|
|
return g_strdup ("C:\\");
|
|
|
|
|
|
|
|
p = (char *) g_path_skip_root (windowsdir);
|
2005-06-08 22:03:12 +02:00
|
|
|
if (G_IS_DIR_SEPARATOR (p[-1]) && p[-2] != ':')
|
|
|
|
p--;
|
|
|
|
*p = '\0';
|
2006-12-28 16:47:42 +01:00
|
|
|
return windowsdir;
|
2005-06-08 22:03:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return g_strdup ("C:\\");
|
|
|
|
}
|
|
|
|
|
2004-08-25 02:39:13 +02:00
|
|
|
#endif
|
|
|
|
|
1998-12-15 06:28:02 +01:00
|
|
|
/* HOLDS: g_utils_global_lock */
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
static UserDatabaseEntry *
|
|
|
|
g_get_user_database_entry (void)
|
1998-07-10 07:51:17 +02:00
|
|
|
{
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
static UserDatabaseEntry *entry;
|
2004-11-28 19:39:24 +01:00
|
|
|
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
if (g_once_init_enter (&entry))
|
2005-08-17 14:00:51 +02:00
|
|
|
{
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
static UserDatabaseEntry e;
|
2012-12-02 18:07:24 +01:00
|
|
|
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
#ifdef G_OS_UNIX
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
{
|
|
|
|
struct passwd *pw = NULL;
|
|
|
|
gpointer buffer = NULL;
|
|
|
|
gint error;
|
|
|
|
gchar *logname;
|
2005-12-04 08:00:50 +01:00
|
|
|
|
2015-10-16 13:36:58 +02:00
|
|
|
# if defined (HAVE_GETPWUID_R)
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
struct passwd pwd;
|
|
|
|
# ifdef _SC_GETPW_R_SIZE_MAX
|
|
|
|
/* This reurns the maximum length */
|
|
|
|
glong bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
|
|
|
|
|
|
|
|
if (bufsize < 0)
|
|
|
|
bufsize = 64;
|
1999-04-22 15:16:10 +02:00
|
|
|
# else /* _SC_GETPW_R_SIZE_MAX */
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
glong bufsize = 64;
|
1999-04-22 15:16:10 +02:00
|
|
|
# endif /* _SC_GETPW_R_SIZE_MAX */
|
2005-12-04 08:00:50 +01:00
|
|
|
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
logname = (gchar *) g_getenv ("LOGNAME");
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
g_free (buffer);
|
|
|
|
/* we allocate 6 extra bytes to work around a bug in
|
|
|
|
* Mac OS < 10.3. See #156446
|
|
|
|
*/
|
|
|
|
buffer = g_malloc (bufsize + 6);
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
if (logname) {
|
|
|
|
error = getpwnam_r (logname, &pwd, buffer, bufsize, &pw);
|
|
|
|
if (!pw || (pw->pw_uid != getuid ())) {
|
|
|
|
/* LOGNAME is lying, fall back to looking up the uid */
|
|
|
|
error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
|
|
|
|
}
|
|
|
|
error = error < 0 ? errno : error;
|
|
|
|
|
|
|
|
if (!pw)
|
|
|
|
{
|
|
|
|
/* we bail out prematurely if the user id can't be found
|
|
|
|
* (should be pretty rare case actually), or if the buffer
|
|
|
|
* should be sufficiently big and lookups are still not
|
|
|
|
* successful.
|
|
|
|
*/
|
|
|
|
if (error == 0 || error == ENOENT)
|
|
|
|
{
|
|
|
|
g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
|
|
|
|
(gulong) getuid ());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (bufsize > 32 * 1024)
|
|
|
|
{
|
|
|
|
g_warning ("getpwuid_r(): failed due to: %s.",
|
|
|
|
g_strerror (error));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bufsize *= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (!pw);
|
2015-10-16 13:36:58 +02:00
|
|
|
# endif /* HAVE_GETPWUID_R */
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
|
|
|
|
if (!pw)
|
|
|
|
{
|
|
|
|
pw = getpwuid (getuid ());
|
|
|
|
}
|
|
|
|
if (pw)
|
|
|
|
{
|
|
|
|
e.user_name = g_strdup (pw->pw_name);
|
|
|
|
|
2012-11-28 16:55:54 +01:00
|
|
|
#ifndef __BIONIC__
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
if (pw->pw_gecos && *pw->pw_gecos != '\0')
|
|
|
|
{
|
|
|
|
gchar **gecos_fields;
|
|
|
|
gchar **name_parts;
|
|
|
|
|
|
|
|
/* split the gecos field and substitute '&' */
|
|
|
|
gecos_fields = g_strsplit (pw->pw_gecos, ",", 0);
|
|
|
|
name_parts = g_strsplit (gecos_fields[0], "&", 0);
|
|
|
|
pw->pw_name[0] = g_ascii_toupper (pw->pw_name[0]);
|
|
|
|
e.real_name = g_strjoinv (pw->pw_name, name_parts);
|
|
|
|
g_strfreev (gecos_fields);
|
|
|
|
g_strfreev (name_parts);
|
|
|
|
}
|
2012-11-28 16:55:54 +01:00
|
|
|
#endif
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
|
|
|
|
if (!e.home_dir)
|
|
|
|
e.home_dir = g_strdup (pw->pw_dir);
|
|
|
|
}
|
|
|
|
g_free (buffer);
|
1999-01-20 16:06:46 +01:00
|
|
|
}
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
#endif /* G_OS_UNIX */
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
|
2004-11-28 19:39:24 +01:00
|
|
|
#ifdef G_OS_WIN32
|
2006-09-02 01:32:05 +02:00
|
|
|
{
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
guint len = UNLEN+1;
|
|
|
|
wchar_t buffer[UNLEN+1];
|
|
|
|
|
|
|
|
if (GetUserNameW (buffer, (LPDWORD) &len))
|
|
|
|
{
|
|
|
|
e.user_name = g_utf16_to_utf8 (buffer, -1, NULL, NULL, NULL);
|
|
|
|
e.real_name = g_strdup (e.user_name);
|
|
|
|
}
|
2006-09-02 01:32:05 +02:00
|
|
|
}
|
2004-11-28 19:39:24 +01:00
|
|
|
#endif /* G_OS_WIN32 */
|
2002-03-05 06:46:08 +01:00
|
|
|
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
if (!e.user_name)
|
|
|
|
e.user_name = g_strdup ("somebody");
|
|
|
|
if (!e.real_name)
|
|
|
|
e.real_name = g_strdup ("Unknown");
|
1998-07-10 07:51:17 +02:00
|
|
|
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
g_once_init_leave (&entry, &e);
|
|
|
|
}
|
2005-08-17 14:00:51 +02:00
|
|
|
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
return entry;
|
2005-08-17 14:00:51 +02:00
|
|
|
}
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_get_user_name:
|
|
|
|
*
|
|
|
|
* Gets the user name of the current user. The encoding of the returned
|
|
|
|
* string is system-defined. On UNIX, it might be the preferred file name
|
|
|
|
* encoding, or something else, and there is no guarantee that it is even
|
|
|
|
* consistent on a machine. On Windows, it is always UTF-8.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): the user name of the current user.
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
1998-07-10 07:51:17 +02:00
|
|
|
g_get_user_name (void)
|
|
|
|
{
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
UserDatabaseEntry *entry;
|
|
|
|
|
|
|
|
entry = g_get_user_database_entry ();
|
|
|
|
|
|
|
|
return entry->user_name;
|
1998-07-10 07:51:17 +02:00
|
|
|
}
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_get_real_name:
|
|
|
|
*
|
2014-02-06 02:17:46 +01:00
|
|
|
* Gets the real name of the user. This usually comes from the user's
|
|
|
|
* entry in the `passwd` file. The encoding of the returned string is
|
|
|
|
* system-defined. (On Windows, it is, however, always UTF-8.) If the
|
|
|
|
* real user name cannot be determined, the string "Unknown" is
|
2005-02-02 07:07:14 +01:00
|
|
|
* returned.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): the user's real name.
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
1998-07-10 07:51:17 +02:00
|
|
|
g_get_real_name (void)
|
|
|
|
{
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
UserDatabaseEntry *entry;
|
|
|
|
|
|
|
|
entry = g_get_user_database_entry ();
|
|
|
|
|
|
|
|
return entry->real_name;
|
1998-07-10 07:51:17 +02:00
|
|
|
}
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_get_home_dir:
|
|
|
|
*
|
2012-12-02 18:07:24 +01:00
|
|
|
* Gets the current user's home directory.
|
|
|
|
*
|
|
|
|
* As with most UNIX tools, this function will return the value of the
|
2014-02-06 01:32:41 +01:00
|
|
|
* `HOME` environment variable if it is set to an existing absolute path
|
2014-02-06 02:17:46 +01:00
|
|
|
* name, falling back to the `passwd` file in the case that it is unset.
|
2005-02-02 07:07:14 +01:00
|
|
|
*
|
2014-02-06 01:32:41 +01:00
|
|
|
* If the path given in `HOME` is non-absolute, does not exist, or is
|
|
|
|
* not a directory, the result is undefined.
|
2005-02-02 07:07:14 +01:00
|
|
|
*
|
2014-02-06 01:32:41 +01:00
|
|
|
* Before version 2.36 this function would ignore the `HOME` environment
|
2014-02-06 02:17:46 +01:00
|
|
|
* variable, taking the value from the `passwd` database instead. This was
|
|
|
|
* changed to increase the compatibility of GLib with other programs (and
|
|
|
|
* the XDG basedir specification) and to increase testability of programs
|
|
|
|
* based on GLib (by making it easier to run them from test frameworks).
|
2014-01-31 20:56:10 +01:00
|
|
|
*
|
|
|
|
* If your program has a strong requirement for either the new or the
|
|
|
|
* old behaviour (and if you don't wish to increase your GLib
|
|
|
|
* dependency to ensure that the new behaviour is in effect) then you
|
2014-02-06 01:32:41 +01:00
|
|
|
* should either directly check the `HOME` environment variable yourself
|
|
|
|
* or unset it before calling any functions in GLib.
|
2007-06-18 21:12:10 +02:00
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): the current user's home directory
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
1998-07-10 07:51:17 +02:00
|
|
|
g_get_home_dir (void)
|
|
|
|
{
|
gutils: stop g_get_home_dir() from reading passwd
In the case that the "HOME" environment variable is set (as it is under
normal circumstances), we don't really need to be opening /etc/passwd.
For historical reasons (ie: how we used to ignore $HOME) and due to the
grouping of many unrelated things together (reading username, hostname,
home directory, tmpdir, etc.) into one function we were still opening
/etc/passwd in g_get_home_dir(), even if $HOME was set.
Since earlier commits removed code from it, all that remains in
g_get_any_init_do() is the logic for dealing with $HOME and reading the
password database.
We now split the logic to deal with $HOME into g_get_home_dir(). With
only the password database functionality remaining, g_get_any_init_do()
is renamed to g_get_user_database_entry() and modified not to set global
variables but rather return a struct. If g_get_home_dir() cannot find
$HOME, it falls back to calling g_get_user_database_entry() and using
the home directory from there.
Use of the 'g_utils_global' lock is further reduced by using
g_once_init_enter() to protect the critical sections in each of
g_get_user_database_entry() and g_get_home_dir().
Finally, the g_get_user_name() and g_get_real_name() functions are
modified to use the new regime.
https://bugzilla.gnome.org/show_bug.cgi?id=693204
2013-02-04 14:41:25 +01:00
|
|
|
static gchar *home_dir;
|
|
|
|
|
|
|
|
if (g_once_init_enter (&home_dir))
|
|
|
|
{
|
|
|
|
gchar *tmp;
|
|
|
|
|
|
|
|
/* We first check HOME and use it if it is set */
|
|
|
|
tmp = g_strdup (g_getenv ("HOME"));
|
|
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
/* Only believe HOME if it is an absolute path and exists.
|
|
|
|
*
|
|
|
|
* We only do this check on Windows for a couple of reasons.
|
|
|
|
* Historically, we only did it there because we used to ignore $HOME
|
|
|
|
* on UNIX. There are concerns about enabling it now on UNIX because
|
|
|
|
* of things like autofs. In short, if the user has a bogus value in
|
|
|
|
* $HOME then they get what they pay for...
|
|
|
|
*/
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (!(g_path_is_absolute (tmp) &&
|
|
|
|
g_file_test (tmp, G_FILE_TEST_IS_DIR)))
|
|
|
|
{
|
|
|
|
g_free (tmp);
|
|
|
|
tmp = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In case HOME is Unix-style (it happens), convert it to
|
|
|
|
* Windows style.
|
|
|
|
*/
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
gchar *p;
|
|
|
|
while ((p = strchr (tmp, '/')) != NULL)
|
|
|
|
*p = '\\';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
/* USERPROFILE is probably the closest equivalent to $HOME? */
|
|
|
|
if (g_getenv ("USERPROFILE") != NULL)
|
|
|
|
tmp = g_strdup (g_getenv ("USERPROFILE"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tmp)
|
|
|
|
tmp = get_special_folder (CSIDL_PROFILE);
|
|
|
|
|
|
|
|
if (!tmp)
|
|
|
|
tmp = get_windows_directory_root ();
|
|
|
|
#endif /* G_OS_WIN32 */
|
|
|
|
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
/* If we didn't get it from any of those methods, we will have
|
|
|
|
* to read the user database entry.
|
|
|
|
*/
|
|
|
|
UserDatabaseEntry *entry;
|
|
|
|
|
|
|
|
entry = g_get_user_database_entry ();
|
|
|
|
|
|
|
|
/* Strictly speaking, we should copy this, but we know that
|
|
|
|
* neither will ever be freed, so don't bother...
|
|
|
|
*/
|
|
|
|
tmp = entry->home_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_once_init_leave (&home_dir, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return home_dir;
|
1998-07-10 07:51:17 +02:00
|
|
|
}
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_get_tmp_dir:
|
|
|
|
*
|
2013-07-29 16:00:20 +02:00
|
|
|
* Gets the directory to use for temporary files.
|
|
|
|
*
|
2014-02-06 01:32:41 +01:00
|
|
|
* On UNIX, this is taken from the `TMPDIR` environment variable.
|
2014-02-06 14:04:52 +01:00
|
|
|
* If the variable is not set, `P_tmpdir` is
|
2014-02-06 01:32:41 +01:00
|
|
|
* used, as defined by the system C library. Failing that, a
|
|
|
|
* hard-coded default of "/tmp" is returned.
|
2013-07-29 16:00:20 +02:00
|
|
|
*
|
2014-02-06 01:32:41 +01:00
|
|
|
* On Windows, the `TEMP` environment variable is used, with the
|
|
|
|
* root directory of the Windows installation (eg: "C:\") used
|
2013-07-29 16:00:20 +02:00
|
|
|
* as a default.
|
|
|
|
*
|
2014-02-06 01:32:41 +01:00
|
|
|
* The encoding of the returned string is system-defined. On Windows,
|
|
|
|
* it is always UTF-8. The return value is never %NULL or the empty
|
|
|
|
* string.
|
2005-02-02 07:07:14 +01:00
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): the directory to use for temporary files.
|
1998-11-01 05:19:54 +01:00
|
|
|
*/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
1998-07-10 07:51:17 +02:00
|
|
|
g_get_tmp_dir (void)
|
|
|
|
{
|
2013-02-04 14:17:08 +01:00
|
|
|
static gchar *tmp_dir;
|
|
|
|
|
|
|
|
if (g_once_init_enter (&tmp_dir))
|
|
|
|
{
|
|
|
|
gchar *tmp;
|
|
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
2013-07-29 16:00:20 +02:00
|
|
|
tmp = g_strdup (g_getenv ("TEMP"));
|
|
|
|
|
2013-02-04 14:17:08 +01:00
|
|
|
if (tmp == NULL || *tmp == '\0')
|
|
|
|
{
|
|
|
|
g_free (tmp);
|
|
|
|
tmp = get_windows_directory_root ();
|
|
|
|
}
|
2013-07-29 16:00:20 +02:00
|
|
|
#else /* G_OS_WIN32 */
|
|
|
|
tmp = g_strdup (g_getenv ("TMPDIR"));
|
2013-02-04 14:17:08 +01:00
|
|
|
|
|
|
|
#ifdef P_tmpdir
|
|
|
|
if (tmp == NULL || *tmp == '\0')
|
|
|
|
{
|
|
|
|
gsize k;
|
|
|
|
g_free (tmp);
|
|
|
|
tmp = g_strdup (P_tmpdir);
|
|
|
|
k = strlen (tmp);
|
|
|
|
if (k > 1 && G_IS_DIR_SEPARATOR (tmp[k - 1]))
|
|
|
|
tmp[k - 1] = '\0';
|
|
|
|
}
|
2013-07-29 16:00:20 +02:00
|
|
|
#endif /* P_tmpdir */
|
2013-02-04 14:17:08 +01:00
|
|
|
|
|
|
|
if (tmp == NULL || *tmp == '\0')
|
|
|
|
{
|
|
|
|
g_free (tmp);
|
|
|
|
tmp = g_strdup ("/tmp");
|
|
|
|
}
|
|
|
|
#endif /* !G_OS_WIN32 */
|
|
|
|
|
|
|
|
g_once_init_leave (&tmp_dir, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmp_dir;
|
1998-07-10 07:51:17 +02:00
|
|
|
}
|
|
|
|
|
2005-06-22 10:54:28 +02:00
|
|
|
/**
|
|
|
|
* g_get_host_name:
|
|
|
|
*
|
|
|
|
* Return a name for the machine.
|
|
|
|
*
|
|
|
|
* The returned name is not necessarily a fully-qualified domain name,
|
|
|
|
* or even present in DNS or some other name service at all. It need
|
|
|
|
* not even be unique on your local network or site, but usually it
|
|
|
|
* is. Callers should not rely on the return value having any specific
|
|
|
|
* properties like uniqueness for security purposes. Even if the name
|
|
|
|
* of the machine is changed while an application is running, the
|
|
|
|
* return value from this function does not change. The returned
|
|
|
|
* string is owned by GLib and should not be modified or freed. If no
|
2005-08-10 23:13:29 +02:00
|
|
|
* name can be determined, a default fixed string "localhost" is
|
2005-06-22 10:54:28 +02:00
|
|
|
* returned.
|
2005-06-22 11:02:41 +02:00
|
|
|
*
|
2005-08-03 22:24:18 +02:00
|
|
|
* Returns: the host name of the machine.
|
|
|
|
*
|
2005-06-22 11:02:41 +02:00
|
|
|
* Since: 2.8
|
2005-06-22 10:54:28 +02:00
|
|
|
*/
|
|
|
|
const gchar *
|
|
|
|
g_get_host_name (void)
|
|
|
|
{
|
2013-02-04 13:49:06 +01:00
|
|
|
static gchar *hostname;
|
|
|
|
|
|
|
|
if (g_once_init_enter (&hostname))
|
|
|
|
{
|
|
|
|
gboolean failed;
|
|
|
|
gchar tmp[100];
|
|
|
|
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
failed = (gethostname (tmp, sizeof (tmp)) == -1);
|
|
|
|
#else
|
|
|
|
DWORD size = sizeof (tmp);
|
|
|
|
failed = (!GetComputerName (tmp, &size));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
g_once_init_leave (&hostname, g_strdup (failed ? "localhost" : tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
return hostname;
|
2005-06-22 10:54:28 +02:00
|
|
|
}
|
|
|
|
|
2003-10-24 05:41:22 +02:00
|
|
|
G_LOCK_DEFINE_STATIC (g_prgname);
|
1998-07-10 07:51:17 +02:00
|
|
|
static gchar *g_prgname = NULL;
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_get_prgname:
|
|
|
|
*
|
2014-02-01 02:34:33 +01:00
|
|
|
* Gets the name of the program. This name should not be localized,
|
|
|
|
* in contrast to g_get_application_name().
|
|
|
|
*
|
|
|
|
* If you are using GDK or GTK+ the program name is set in gdk_init(),
|
2005-02-02 07:07:14 +01:00
|
|
|
* which is called by gtk_init(). The program name is found by taking
|
2014-02-01 02:34:33 +01:00
|
|
|
* the last component of @argv[0].
|
2005-02-02 07:07:14 +01:00
|
|
|
*
|
|
|
|
* Returns: the name of the program. The returned string belongs
|
2014-02-01 02:34:33 +01:00
|
|
|
* to GLib and must not be modified or freed.
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
2013-01-13 18:14:11 +01:00
|
|
|
const gchar*
|
1998-07-10 07:51:17 +02:00
|
|
|
g_get_prgname (void)
|
|
|
|
{
|
1998-12-15 06:28:02 +01:00
|
|
|
gchar* retval;
|
|
|
|
|
2001-10-19 10:09:22 +02:00
|
|
|
G_LOCK (g_prgname);
|
2005-03-20 11:52:38 +01:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
if (g_prgname == NULL)
|
|
|
|
{
|
|
|
|
static gboolean beenhere = FALSE;
|
|
|
|
|
|
|
|
if (!beenhere)
|
|
|
|
{
|
|
|
|
gchar *utf8_buf = NULL;
|
2006-08-30 00:45:00 +02:00
|
|
|
wchar_t buf[MAX_PATH+1];
|
2005-03-20 11:52:38 +01:00
|
|
|
|
|
|
|
beenhere = TRUE;
|
2006-08-30 00:45:00 +02:00
|
|
|
if (GetModuleFileNameW (GetModuleHandle (NULL),
|
|
|
|
buf, G_N_ELEMENTS (buf)) > 0)
|
|
|
|
utf8_buf = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
|
|
|
|
|
2005-03-20 11:52:38 +01:00
|
|
|
if (utf8_buf)
|
|
|
|
{
|
|
|
|
g_prgname = g_path_get_basename (utf8_buf);
|
|
|
|
g_free (utf8_buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
1998-12-15 06:28:02 +01:00
|
|
|
retval = g_prgname;
|
2001-10-19 10:09:22 +02:00
|
|
|
G_UNLOCK (g_prgname);
|
1998-12-15 06:28:02 +01:00
|
|
|
|
|
|
|
return retval;
|
1998-07-10 07:51:17 +02:00
|
|
|
}
|
|
|
|
|
2005-02-02 07:07:14 +01:00
|
|
|
/**
|
|
|
|
* g_set_prgname:
|
|
|
|
* @prgname: the name of the program.
|
|
|
|
*
|
2014-02-01 02:34:33 +01:00
|
|
|
* Sets the name of the program. This name should not be localized,
|
|
|
|
* in contrast to g_set_application_name().
|
|
|
|
*
|
|
|
|
* Note that for thread-safety reasons this function can only be called once.
|
2005-02-02 07:07:14 +01:00
|
|
|
*/
|
1998-07-10 07:51:17 +02:00
|
|
|
void
|
|
|
|
g_set_prgname (const gchar *prgname)
|
|
|
|
{
|
2001-10-19 10:09:22 +02:00
|
|
|
G_LOCK (g_prgname);
|
2009-12-21 15:11:23 +01:00
|
|
|
g_free (g_prgname);
|
|
|
|
g_prgname = g_strdup (prgname);
|
2001-10-19 10:09:22 +02:00
|
|
|
G_UNLOCK (g_prgname);
|
1998-07-10 07:51:17 +02:00
|
|
|
}
|
|
|
|
|
2003-10-24 05:41:22 +02:00
|
|
|
G_LOCK_DEFINE_STATIC (g_application_name);
|
2002-11-08 01:51:25 +01:00
|
|
|
static gchar *g_application_name = NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_get_application_name:
|
|
|
|
*
|
|
|
|
* Gets a human-readable name for the application, as set by
|
|
|
|
* g_set_application_name(). This name should be localized if
|
|
|
|
* possible, and is intended for display to the user. Contrast with
|
|
|
|
* g_get_prgname(), which gets a non-localized name. If
|
|
|
|
* g_set_application_name() has not been called, returns the result of
|
|
|
|
* g_get_prgname() (which may be %NULL if g_set_prgname() has also not
|
|
|
|
* been called).
|
|
|
|
*
|
2014-02-20 01:35:23 +01:00
|
|
|
* Returns: human-readable application name. may return %NULL
|
2002-11-29 00:11:58 +01:00
|
|
|
*
|
|
|
|
* Since: 2.2
|
2002-11-08 01:51:25 +01:00
|
|
|
**/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
2002-11-08 01:51:25 +01:00
|
|
|
g_get_application_name (void)
|
|
|
|
{
|
|
|
|
gchar* retval;
|
|
|
|
|
|
|
|
G_LOCK (g_application_name);
|
|
|
|
retval = g_application_name;
|
|
|
|
G_UNLOCK (g_application_name);
|
|
|
|
|
|
|
|
if (retval == NULL)
|
|
|
|
return g_get_prgname ();
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_set_application_name:
|
|
|
|
* @application_name: localized name of the application
|
|
|
|
*
|
|
|
|
* Sets a human-readable name for the application. This name should be
|
|
|
|
* localized if possible, and is intended for display to the user.
|
|
|
|
* Contrast with g_set_prgname(), which sets a non-localized name.
|
|
|
|
* g_set_prgname() will be called automatically by gtk_init(),
|
|
|
|
* but g_set_application_name() will not.
|
|
|
|
*
|
|
|
|
* Note that for thread safety reasons, this function can only
|
|
|
|
* be called once.
|
|
|
|
*
|
|
|
|
* The application name will be used in contexts such as error messages,
|
|
|
|
* or when displaying an application's name in the task list.
|
|
|
|
*
|
2007-11-09 04:01:01 +01:00
|
|
|
* Since: 2.2
|
2002-11-08 01:51:25 +01:00
|
|
|
**/
|
|
|
|
void
|
|
|
|
g_set_application_name (const gchar *application_name)
|
|
|
|
{
|
|
|
|
gboolean already_set = FALSE;
|
|
|
|
|
|
|
|
G_LOCK (g_application_name);
|
|
|
|
if (g_application_name)
|
|
|
|
already_set = TRUE;
|
|
|
|
else
|
|
|
|
g_application_name = g_strdup (application_name);
|
|
|
|
G_UNLOCK (g_application_name);
|
|
|
|
|
|
|
|
if (already_set)
|
2009-10-23 14:49:38 +02:00
|
|
|
g_warning ("g_set_application_name() called multiple times");
|
2002-11-08 01:51:25 +01:00
|
|
|
}
|
|
|
|
|
2004-08-11 19:53:05 +02:00
|
|
|
/**
|
|
|
|
* g_get_user_data_dir:
|
|
|
|
*
|
|
|
|
* Returns a base directory in which to access application data such
|
|
|
|
* as icons that is customized for a particular user.
|
|
|
|
*
|
2014-02-06 03:23:28 +01:00
|
|
|
* On UNIX platforms this is determined using the mechanisms described
|
|
|
|
* in the
|
|
|
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
|
|
|
* In this case the directory retrieved will be `XDG_DATA_HOME`.
|
2010-06-06 04:57:46 +02:00
|
|
|
*
|
2010-10-14 21:47:25 +02:00
|
|
|
* On Windows this is the folder to use for local (as opposed to
|
|
|
|
* roaming) application data. See documentation for
|
|
|
|
* CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
|
|
|
|
* what g_get_user_config_dir() returns.
|
2010-06-06 04:57:46 +02:00
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): a string owned by GLib that must not be modified
|
2004-08-11 19:53:05 +02:00
|
|
|
* or freed.
|
|
|
|
* Since: 2.6
|
|
|
|
**/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
2004-08-11 19:53:05 +02:00
|
|
|
g_get_user_data_dir (void)
|
|
|
|
{
|
|
|
|
gchar *data_dir;
|
|
|
|
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
|
|
|
if (!g_user_data_dir)
|
|
|
|
{
|
2004-08-25 02:39:13 +02:00
|
|
|
#ifdef G_OS_WIN32
|
2010-10-14 21:47:25 +02:00
|
|
|
data_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
|
2004-08-25 02:39:13 +02:00
|
|
|
#else
|
2004-08-11 19:53:05 +02:00
|
|
|
data_dir = (gchar *) g_getenv ("XDG_DATA_HOME");
|
|
|
|
|
|
|
|
if (data_dir && data_dir[0])
|
|
|
|
data_dir = g_strdup (data_dir);
|
2005-03-09 03:08:34 +01:00
|
|
|
#endif
|
|
|
|
if (!data_dir || !data_dir[0])
|
2004-08-23 07:36:48 +02:00
|
|
|
{
|
2013-02-04 14:40:03 +01:00
|
|
|
const gchar *home_dir = g_get_home_dir ();
|
2004-08-23 07:36:48 +02:00
|
|
|
|
2013-02-04 14:40:03 +01:00
|
|
|
if (home_dir)
|
|
|
|
data_dir = g_build_filename (home_dir, ".local", "share", NULL);
|
2005-03-09 03:08:34 +01:00
|
|
|
else
|
2013-02-04 14:40:03 +01:00
|
|
|
data_dir = g_build_filename (g_get_tmp_dir (), g_get_user_name (), ".local", "share", NULL);
|
2004-08-23 07:36:48 +02:00
|
|
|
}
|
2004-10-29 22:58:04 +02:00
|
|
|
|
2004-08-11 19:53:05 +02:00
|
|
|
g_user_data_dir = data_dir;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
data_dir = g_user_data_dir;
|
|
|
|
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
|
|
|
|
return data_dir;
|
|
|
|
}
|
|
|
|
|
2007-06-05 19:36:17 +02:00
|
|
|
static void
|
|
|
|
g_init_user_config_dir (void)
|
2004-08-11 19:53:05 +02:00
|
|
|
{
|
2007-06-05 19:36:17 +02:00
|
|
|
gchar *config_dir;
|
2004-08-11 19:53:05 +02:00
|
|
|
|
|
|
|
if (!g_user_config_dir)
|
|
|
|
{
|
2004-08-25 02:39:13 +02:00
|
|
|
#ifdef G_OS_WIN32
|
2010-10-14 21:47:25 +02:00
|
|
|
config_dir = get_special_folder (CSIDL_LOCAL_APPDATA);
|
2004-08-25 02:39:13 +02:00
|
|
|
#else
|
|
|
|
config_dir = (gchar *) g_getenv ("XDG_CONFIG_HOME");
|
2004-10-29 22:58:04 +02:00
|
|
|
|
2004-08-25 02:39:13 +02:00
|
|
|
if (config_dir && config_dir[0])
|
|
|
|
config_dir = g_strdup (config_dir);
|
2005-03-09 03:08:34 +01:00
|
|
|
#endif
|
|
|
|
if (!config_dir || !config_dir[0])
|
2004-08-25 02:39:13 +02:00
|
|
|
{
|
2013-02-04 14:40:03 +01:00
|
|
|
const gchar *home_dir = g_get_home_dir ();
|
2005-08-17 14:00:51 +02:00
|
|
|
|
2013-02-04 14:40:03 +01:00
|
|
|
if (home_dir)
|
|
|
|
config_dir = g_build_filename (home_dir, ".config", NULL);
|
2005-03-09 03:08:34 +01:00
|
|
|
else
|
2013-02-04 14:40:03 +01:00
|
|
|
config_dir = g_build_filename (g_get_tmp_dir (), g_get_user_name (), ".config", NULL);
|
2004-08-25 02:39:13 +02:00
|
|
|
}
|
2007-06-05 19:36:17 +02:00
|
|
|
|
2004-08-25 02:39:13 +02:00
|
|
|
g_user_config_dir = config_dir;
|
2004-08-11 19:53:05 +02:00
|
|
|
}
|
2007-06-05 19:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_get_user_config_dir:
|
|
|
|
*
|
|
|
|
* Returns a base directory in which to store user-specific application
|
|
|
|
* configuration information such as user preferences and settings.
|
|
|
|
*
|
2014-02-06 03:23:28 +01:00
|
|
|
* On UNIX platforms this is determined using the mechanisms described
|
|
|
|
* in the
|
|
|
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
|
|
|
* In this case the directory retrieved will be `XDG_CONFIG_HOME`.
|
2010-06-05 18:34:38 +02:00
|
|
|
*
|
2010-10-14 21:47:25 +02:00
|
|
|
* On Windows this is the folder to use for local (as opposed to
|
|
|
|
* roaming) application data. See documentation for
|
|
|
|
* CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
|
|
|
|
* what g_get_user_data_dir() returns.
|
2010-06-05 18:34:38 +02:00
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): a string owned by GLib that must not be modified
|
2007-06-05 19:36:17 +02:00
|
|
|
* or freed.
|
|
|
|
* Since: 2.6
|
|
|
|
**/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
2007-06-05 19:36:17 +02:00
|
|
|
g_get_user_config_dir (void)
|
|
|
|
{
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
|
|
|
g_init_user_config_dir ();
|
2004-08-11 19:53:05 +02:00
|
|
|
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
|
2007-06-05 19:36:17 +02:00
|
|
|
return g_user_config_dir;
|
2004-08-11 19:53:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_get_user_cache_dir:
|
|
|
|
*
|
|
|
|
* Returns a base directory in which to store non-essential, cached
|
|
|
|
* data specific to particular user.
|
|
|
|
*
|
2014-02-06 03:23:28 +01:00
|
|
|
* On UNIX platforms this is determined using the mechanisms described
|
|
|
|
* in the
|
|
|
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
2010-06-06 05:05:15 +02:00
|
|
|
* In this case the directory retrieved will be XDG_CACHE_HOME.
|
|
|
|
*
|
|
|
|
* On Windows is the directory that serves as a common repository for
|
|
|
|
* temporary Internet files. A typical path is
|
|
|
|
* C:\Documents and Settings\username\Local Settings\Temporary Internet Files.
|
|
|
|
* See documentation for CSIDL_INTERNET_CACHE.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): a string owned by GLib that must not be modified
|
2004-08-11 19:53:05 +02:00
|
|
|
* or freed.
|
|
|
|
* Since: 2.6
|
|
|
|
**/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
2004-08-11 19:53:05 +02:00
|
|
|
g_get_user_cache_dir (void)
|
|
|
|
{
|
|
|
|
gchar *cache_dir;
|
|
|
|
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
|
|
|
if (!g_user_cache_dir)
|
|
|
|
{
|
2004-08-25 02:39:13 +02:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
cache_dir = get_special_folder (CSIDL_INTERNET_CACHE); /* XXX correct? */
|
|
|
|
#else
|
2004-08-11 19:53:05 +02:00
|
|
|
cache_dir = (gchar *) g_getenv ("XDG_CACHE_HOME");
|
2005-03-09 03:08:34 +01:00
|
|
|
|
2004-08-11 19:53:05 +02:00
|
|
|
if (cache_dir && cache_dir[0])
|
|
|
|
cache_dir = g_strdup (cache_dir);
|
2005-03-09 03:08:34 +01:00
|
|
|
#endif
|
|
|
|
if (!cache_dir || !cache_dir[0])
|
2004-08-23 07:36:48 +02:00
|
|
|
{
|
2013-02-04 14:40:03 +01:00
|
|
|
const gchar *home_dir = g_get_home_dir ();
|
|
|
|
|
|
|
|
if (home_dir)
|
|
|
|
cache_dir = g_build_filename (home_dir, ".cache", NULL);
|
2005-03-09 03:08:34 +01:00
|
|
|
else
|
2013-02-04 14:40:03 +01:00
|
|
|
cache_dir = g_build_filename (g_get_tmp_dir (), g_get_user_name (), ".cache", NULL);
|
2004-08-23 07:36:48 +02:00
|
|
|
}
|
2004-08-11 19:53:05 +02:00
|
|
|
g_user_cache_dir = cache_dir;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cache_dir = g_user_cache_dir;
|
|
|
|
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
|
|
|
|
return cache_dir;
|
|
|
|
}
|
|
|
|
|
2010-11-06 22:34:40 +01:00
|
|
|
/**
|
|
|
|
* g_get_user_runtime_dir:
|
|
|
|
*
|
|
|
|
* Returns a directory that is unique to the current user on the local
|
|
|
|
* system.
|
|
|
|
*
|
2014-02-06 03:23:28 +01:00
|
|
|
* On UNIX platforms this is determined using the mechanisms described
|
|
|
|
* in the
|
|
|
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
|
|
|
* This is the directory
|
2014-02-06 01:32:41 +01:00
|
|
|
* specified in the `XDG_RUNTIME_DIR` environment variable.
|
2016-03-08 21:34:26 +01:00
|
|
|
* In the case that this variable is not set, we return the value of
|
|
|
|
* g_get_user_cache_dir(), after verifying that it exists.
|
2010-11-06 22:34:40 +01:00
|
|
|
*
|
|
|
|
* On Windows this is the folder to use for local (as opposed to
|
|
|
|
* roaming) application data. See documentation for
|
|
|
|
* CSIDL_LOCAL_APPDATA. Note that on Windows it thus is the same as
|
|
|
|
* what g_get_user_config_dir() returns.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): a string owned by GLib that must not be
|
|
|
|
* modified or freed.
|
2010-11-29 07:16:02 +01:00
|
|
|
*
|
|
|
|
* Since: 2.28
|
2010-11-06 22:34:40 +01:00
|
|
|
**/
|
|
|
|
const gchar *
|
|
|
|
g_get_user_runtime_dir (void)
|
|
|
|
{
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
static const gchar *runtime_dir;
|
|
|
|
|
2016-03-08 21:34:26 +01:00
|
|
|
if (g_once_init_enter (&runtime_dir))
|
2010-11-06 22:34:40 +01:00
|
|
|
{
|
2016-03-08 21:34:26 +01:00
|
|
|
const gchar *dir;
|
2010-11-06 22:34:40 +01:00
|
|
|
|
2016-03-08 21:34:26 +01:00
|
|
|
dir = g_strdup (getenv ("XDG_RUNTIME_DIR"));
|
2010-11-06 22:34:40 +01:00
|
|
|
|
2016-03-08 21:34:26 +01:00
|
|
|
if (dir == NULL)
|
|
|
|
{
|
|
|
|
/* No need to strdup this one since it is valid forever. */
|
|
|
|
dir = g_get_user_cache_dir ();
|
|
|
|
|
|
|
|
/* The user should be able to rely on the directory existing
|
|
|
|
* when the function returns. Probably it already does, but
|
|
|
|
* let's make sure. Just do mkdir() directly since it will be
|
|
|
|
* no more expensive than a stat() in the case that the
|
|
|
|
* directory already exists and is a lot easier.
|
|
|
|
*
|
|
|
|
* $XDG_CACHE_HOME is probably ~/.cache/ so as long as $HOME
|
|
|
|
* exists this will work. If the user changed $XDG_CACHE_HOME
|
|
|
|
* then they can make sure that it exists...
|
|
|
|
*/
|
|
|
|
(void) mkdir (dir, 0700);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (dir != NULL);
|
2010-11-06 22:34:40 +01:00
|
|
|
|
2016-03-08 21:34:26 +01:00
|
|
|
g_once_init_leave (&runtime_dir, dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
return runtime_dir;
|
|
|
|
#else /* Windows */
|
2010-11-06 22:34:40 +01:00
|
|
|
return g_get_user_cache_dir ();
|
2016-03-08 21:34:26 +01:00
|
|
|
#endif
|
2010-11-06 22:34:40 +01:00
|
|
|
}
|
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
#ifdef HAVE_CARBON
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
find_folder (OSType type)
|
|
|
|
{
|
|
|
|
gchar *filename = NULL;
|
|
|
|
FSRef found;
|
|
|
|
|
|
|
|
if (FSFindFolder (kUserDomain, type, kDontCreateFolder, &found) == noErr)
|
|
|
|
{
|
|
|
|
CFURLRef url = CFURLCreateFromFSRef (kCFAllocatorSystemDefault, &found);
|
|
|
|
|
|
|
|
if (url)
|
|
|
|
{
|
|
|
|
CFStringRef path = CFURLCopyFileSystemPath (url, kCFURLPOSIXPathStyle);
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
filename = g_strdup (CFStringGetCStringPtr (path, kCFStringEncodingUTF8));
|
|
|
|
|
|
|
|
if (! filename)
|
|
|
|
{
|
|
|
|
filename = g_new0 (gchar, CFStringGetLength (path) * 3 + 1);
|
|
|
|
|
|
|
|
CFStringGetCString (path, filename,
|
|
|
|
CFStringGetLength (path) * 3 + 1,
|
|
|
|
kCFStringEncodingUTF8);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease (path);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease (url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
load_user_special_dirs (void)
|
|
|
|
{
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = find_folder (kDesktopFolderType);
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = find_folder (kDocumentsFolderType);
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = find_folder (kDesktopFolderType); /* XXX correct ? */
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = find_folder (kMusicDocumentsFolderType);
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = find_folder (kPictureDocumentsFolderType);
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = NULL;
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = NULL;
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = find_folder (kMovieDocumentsFolderType);
|
|
|
|
}
|
|
|
|
|
2014-06-10 19:43:27 +02:00
|
|
|
#elif defined(G_OS_WIN32)
|
2007-06-04 16:54:49 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
load_user_special_dirs (void)
|
|
|
|
{
|
2008-05-12 08:58:50 +02:00
|
|
|
typedef HRESULT (WINAPI *t_SHGetKnownFolderPath) (const GUID *rfid,
|
|
|
|
DWORD dwFlags,
|
|
|
|
HANDLE hToken,
|
|
|
|
PWSTR *ppszPath);
|
|
|
|
t_SHGetKnownFolderPath p_SHGetKnownFolderPath;
|
2010-09-02 20:56:02 +02:00
|
|
|
|
2008-05-12 08:58:50 +02:00
|
|
|
static const GUID FOLDERID_Downloads =
|
|
|
|
{ 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
|
|
|
|
static const GUID FOLDERID_Public =
|
|
|
|
{ 0xDFDF76A2, 0xC82A, 0x4D63, { 0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85 } };
|
2010-09-02 20:56:02 +02:00
|
|
|
|
2008-05-12 08:58:50 +02:00
|
|
|
wchar_t *wcp;
|
|
|
|
|
2010-09-02 20:56:02 +02:00
|
|
|
p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (GetModuleHandle ("shell32.dll"),
|
2008-05-12 08:58:50 +02:00
|
|
|
"SHGetKnownFolderPath");
|
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
|
2007-06-06 21:13:45 +02:00
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = get_special_folder (CSIDL_PERSONAL);
|
2008-05-12 08:58:50 +02:00
|
|
|
|
|
|
|
if (p_SHGetKnownFolderPath == NULL)
|
|
|
|
{
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wcp = NULL;
|
|
|
|
(*p_SHGetKnownFolderPath) (&FOLDERID_Downloads, 0, NULL, &wcp);
|
2011-01-28 03:57:57 +01:00
|
|
|
if (wcp)
|
|
|
|
{
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
|
|
|
|
if (g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] == NULL)
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
|
|
|
|
CoTaskMemFree (wcp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
|
2008-05-12 08:58:50 +02:00
|
|
|
}
|
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = get_special_folder (CSIDL_MYMUSIC);
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = get_special_folder (CSIDL_MYPICTURES);
|
2008-05-12 08:58:50 +02:00
|
|
|
|
|
|
|
if (p_SHGetKnownFolderPath == NULL)
|
|
|
|
{
|
|
|
|
/* XXX */
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wcp = NULL;
|
|
|
|
(*p_SHGetKnownFolderPath) (&FOLDERID_Public, 0, NULL, &wcp);
|
2011-01-28 03:57:57 +01:00
|
|
|
if (wcp)
|
|
|
|
{
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
|
|
|
|
if (g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] == NULL)
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
|
|
|
|
CoTaskMemFree (wcp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
|
2008-05-12 08:58:50 +02:00
|
|
|
}
|
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = get_special_folder (CSIDL_TEMPLATES);
|
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = get_special_folder (CSIDL_MYVIDEO);
|
|
|
|
}
|
|
|
|
|
2014-06-10 19:43:27 +02:00
|
|
|
#else /* default is unix */
|
2007-06-04 16:54:49 +02:00
|
|
|
|
|
|
|
/* adapted from xdg-user-dir-lookup.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007 Red Hat Inc.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person
|
|
|
|
* obtaining a copy of this software and associated documentation files
|
|
|
|
* (the "Software"), to deal in the Software without restriction,
|
|
|
|
* including without limitation the rights to use, copy, modify, merge,
|
|
|
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
|
|
* and to permit persons to whom the Software is furnished to do so,
|
|
|
|
* subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be
|
2007-06-06 21:13:45 +02:00
|
|
|
* included in all copies or substantial portions of the Software.
|
2007-06-04 16:54:49 +02:00
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
load_user_special_dirs (void)
|
|
|
|
{
|
|
|
|
gchar *config_file;
|
|
|
|
gchar *data;
|
|
|
|
gchar **lines;
|
|
|
|
gint n_lines, i;
|
|
|
|
|
2007-06-05 19:36:17 +02:00
|
|
|
g_init_user_config_dir ();
|
|
|
|
config_file = g_build_filename (g_user_config_dir,
|
2007-06-04 16:54:49 +02:00
|
|
|
"user-dirs.dirs",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (!g_file_get_contents (config_file, &data, NULL, NULL))
|
|
|
|
{
|
|
|
|
g_free (config_file);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lines = g_strsplit (data, "\n", -1);
|
|
|
|
n_lines = g_strv_length (lines);
|
|
|
|
g_free (data);
|
|
|
|
|
|
|
|
for (i = 0; i < n_lines; i++)
|
|
|
|
{
|
|
|
|
gchar *buffer = lines[i];
|
|
|
|
gchar *d, *p;
|
|
|
|
gint len;
|
|
|
|
gboolean is_relative = FALSE;
|
|
|
|
GUserDirectory directory;
|
|
|
|
|
|
|
|
/* Remove newline at end */
|
|
|
|
len = strlen (buffer);
|
|
|
|
if (len > 0 && buffer[len - 1] == '\n')
|
|
|
|
buffer[len - 1] = 0;
|
|
|
|
|
|
|
|
p = buffer;
|
|
|
|
while (*p == ' ' || *p == '\t')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (strncmp (p, "XDG_DESKTOP_DIR", strlen ("XDG_DESKTOP_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_DESKTOP;
|
|
|
|
p += strlen ("XDG_DESKTOP_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_DOCUMENTS_DIR", strlen ("XDG_DOCUMENTS_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_DOCUMENTS;
|
|
|
|
p += strlen ("XDG_DOCUMENTS_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_DOWNLOAD_DIR", strlen ("XDG_DOWNLOAD_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_DOWNLOAD;
|
|
|
|
p += strlen ("XDG_DOWNLOAD_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_MUSIC_DIR", strlen ("XDG_MUSIC_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_MUSIC;
|
|
|
|
p += strlen ("XDG_MUSIC_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_PICTURES_DIR", strlen ("XDG_PICTURES_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_PICTURES;
|
|
|
|
p += strlen ("XDG_PICTURES_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_PUBLICSHARE_DIR", strlen ("XDG_PUBLICSHARE_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_PUBLIC_SHARE;
|
|
|
|
p += strlen ("XDG_PUBLICSHARE_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_TEMPLATES_DIR", strlen ("XDG_TEMPLATES_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_TEMPLATES;
|
|
|
|
p += strlen ("XDG_TEMPLATES_DIR");
|
|
|
|
}
|
|
|
|
else if (strncmp (p, "XDG_VIDEOS_DIR", strlen ("XDG_VIDEOS_DIR")) == 0)
|
|
|
|
{
|
|
|
|
directory = G_USER_DIRECTORY_VIDEOS;
|
|
|
|
p += strlen ("XDG_VIDEOS_DIR");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
|
|
|
|
while (*p == ' ' || *p == '\t')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p != '=')
|
|
|
|
continue;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
while (*p == ' ' || *p == '\t')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p != '"')
|
|
|
|
continue;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (strncmp (p, "$HOME", 5) == 0)
|
|
|
|
{
|
|
|
|
p += 5;
|
|
|
|
is_relative = TRUE;
|
|
|
|
}
|
|
|
|
else if (*p != '/')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
d = strrchr (p, '"');
|
|
|
|
if (!d)
|
|
|
|
continue;
|
|
|
|
*d = 0;
|
|
|
|
|
|
|
|
d = p;
|
|
|
|
|
|
|
|
/* remove trailing slashes */
|
|
|
|
len = strlen (d);
|
|
|
|
if (d[len - 1] == '/')
|
|
|
|
d[len - 1] = 0;
|
|
|
|
|
|
|
|
if (is_relative)
|
2007-06-05 19:36:17 +02:00
|
|
|
{
|
2013-02-04 14:40:03 +01:00
|
|
|
g_user_special_dirs[directory] = g_build_filename (g_get_home_dir (), d, NULL);
|
2007-06-05 19:36:17 +02:00
|
|
|
}
|
2007-06-04 16:54:49 +02:00
|
|
|
else
|
|
|
|
g_user_special_dirs[directory] = g_strdup (d);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev (lines);
|
|
|
|
g_free (config_file);
|
|
|
|
}
|
|
|
|
|
2014-06-10 19:43:27 +02:00
|
|
|
#endif /* platform-specific load_user_special_dirs implementations */
|
2007-06-04 16:54:49 +02:00
|
|
|
|
2009-06-15 13:18:22 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* g_reload_user_special_dirs_cache:
|
|
|
|
*
|
|
|
|
* Resets the cache used for g_get_user_special_dir(), so
|
|
|
|
* that the latest on-disk version is used. Call this only
|
|
|
|
* if you just changed the data on disk yourself.
|
|
|
|
*
|
|
|
|
* Due to threadsafety issues this may cause leaking of strings
|
|
|
|
* that were previously returned from g_get_user_special_dir()
|
|
|
|
* that can't be freed. We ensure to only leak the data for
|
|
|
|
* the directories that actually changed value though.
|
|
|
|
*
|
|
|
|
* Since: 2.22
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
g_reload_user_special_dirs_cache (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
|
|
|
if (g_user_special_dirs != NULL)
|
|
|
|
{
|
|
|
|
/* save a copy of the pointer, to check if some memory can be preserved */
|
|
|
|
char **old_g_user_special_dirs = g_user_special_dirs;
|
|
|
|
char *old_val;
|
|
|
|
|
|
|
|
/* recreate and reload our cache */
|
|
|
|
g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
|
|
|
|
load_user_special_dirs ();
|
|
|
|
|
|
|
|
/* only leak changed directories */
|
|
|
|
for (i = 0; i < G_USER_N_DIRECTORIES; i++)
|
|
|
|
{
|
2012-05-22 21:56:10 +02:00
|
|
|
old_val = old_g_user_special_dirs[i];
|
|
|
|
if (g_user_special_dirs[i] == NULL)
|
2009-06-15 13:18:22 +02:00
|
|
|
{
|
2012-05-22 21:56:10 +02:00
|
|
|
g_user_special_dirs[i] = old_val;
|
2009-06-15 13:18:22 +02:00
|
|
|
}
|
2012-05-22 21:56:10 +02:00
|
|
|
else if (g_strcmp0 (old_val, g_user_special_dirs[i]) == 0)
|
|
|
|
{
|
|
|
|
/* don't leak */
|
|
|
|
g_free (g_user_special_dirs[i]);
|
|
|
|
g_user_special_dirs[i] = old_val;
|
|
|
|
}
|
|
|
|
else
|
2009-06-15 13:18:22 +02:00
|
|
|
g_free (old_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free the old array */
|
|
|
|
g_free (old_g_user_special_dirs);
|
|
|
|
}
|
|
|
|
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
}
|
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
/**
|
|
|
|
* g_get_user_special_dir:
|
|
|
|
* @directory: the logical id of special directory
|
|
|
|
*
|
|
|
|
* Returns the full path of a special directory using its logical id.
|
|
|
|
*
|
2014-02-06 02:17:46 +01:00
|
|
|
* On UNIX this is done using the XDG special user directories.
|
2008-06-11 18:17:56 +02:00
|
|
|
* For compatibility with existing practise, %G_USER_DIRECTORY_DESKTOP
|
2014-02-06 02:17:46 +01:00
|
|
|
* falls back to `$HOME/Desktop` when XDG special user directories have
|
|
|
|
* not been set up.
|
2007-06-04 16:54:49 +02:00
|
|
|
*
|
2007-06-11 17:31:29 +02:00
|
|
|
* Depending on the platform, the user might be able to change the path
|
|
|
|
* of the special directory without requiring the session to restart; GLib
|
|
|
|
* will not reflect any change once the special directories are loaded.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (type filename): the path to the specified special directory, or
|
|
|
|
* %NULL if the logical id was not found. The returned string is owned by
|
2007-06-04 16:54:49 +02:00
|
|
|
* GLib and should not be modified or freed.
|
|
|
|
*
|
|
|
|
* Since: 2.14
|
|
|
|
*/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar *
|
2007-06-04 16:54:49 +02:00
|
|
|
g_get_user_special_dir (GUserDirectory directory)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
|
|
|
|
directory < G_USER_N_DIRECTORIES, NULL);
|
|
|
|
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
2007-06-11 17:31:29 +02:00
|
|
|
if (G_UNLIKELY (g_user_special_dirs == NULL))
|
2007-06-04 16:54:49 +02:00
|
|
|
{
|
|
|
|
g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
|
2007-06-06 21:05:53 +02:00
|
|
|
|
2007-06-04 16:54:49 +02:00
|
|
|
load_user_special_dirs ();
|
2007-06-06 21:05:53 +02:00
|
|
|
|
|
|
|
/* Special-case desktop for historical compatibility */
|
|
|
|
if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
|
2013-02-04 14:40:03 +01:00
|
|
|
g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = g_build_filename (g_get_home_dir (), "Desktop", NULL);
|
2007-06-04 16:54:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
|
|
|
|
return g_user_special_dirs[directory];
|
|
|
|
}
|
|
|
|
|
2005-04-08 14:03:16 +02:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
|
|
|
#undef g_get_system_data_dirs
|
|
|
|
|
|
|
|
static HMODULE
|
|
|
|
get_module_for_address (gconstpointer address)
|
|
|
|
{
|
|
|
|
/* Holds the g_utils_global lock */
|
|
|
|
|
|
|
|
static gboolean beenhere = FALSE;
|
|
|
|
typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
|
|
|
|
static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
|
2008-02-24 02:07:41 +01:00
|
|
|
HMODULE hmodule = NULL;
|
2005-04-08 14:03:16 +02:00
|
|
|
|
|
|
|
if (!address)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!beenhere)
|
|
|
|
{
|
|
|
|
p_GetModuleHandleExA =
|
2010-09-02 20:56:02 +02:00
|
|
|
(t_GetModuleHandleExA) GetProcAddress (GetModuleHandle ("kernel32.dll"),
|
2005-04-08 14:03:16 +02:00
|
|
|
"GetModuleHandleExA");
|
|
|
|
beenhere = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p_GetModuleHandleExA == NULL ||
|
|
|
|
!(*p_GetModuleHandleExA) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT |
|
|
|
|
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
|
|
|
address, &hmodule))
|
|
|
|
{
|
|
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
|
|
VirtualQuery (address, &mbi, sizeof (mbi));
|
|
|
|
hmodule = (HMODULE) mbi.AllocationBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
return hmodule;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
get_module_share_dir (gconstpointer address)
|
|
|
|
{
|
|
|
|
HMODULE hmodule;
|
2008-02-24 02:07:41 +01:00
|
|
|
gchar *filename;
|
|
|
|
gchar *retval;
|
2005-04-08 14:03:16 +02:00
|
|
|
|
|
|
|
hmodule = get_module_for_address (address);
|
|
|
|
if (hmodule == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2008-02-24 02:07:41 +01:00
|
|
|
filename = g_win32_get_package_installation_directory_of_module (hmodule);
|
2005-04-08 14:03:16 +02:00
|
|
|
retval = g_build_filename (filename, "share", NULL);
|
|
|
|
g_free (filename);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar * const *
|
2012-11-10 16:58:19 +01:00
|
|
|
g_win32_get_system_data_dirs_for_module (void (*address_of_function)(void))
|
2005-04-08 14:03:16 +02:00
|
|
|
{
|
|
|
|
GArray *data_dirs;
|
|
|
|
HMODULE hmodule;
|
|
|
|
static GHashTable *per_module_data_dirs = NULL;
|
|
|
|
gchar **retval;
|
|
|
|
gchar *p;
|
2008-02-24 02:07:41 +01:00
|
|
|
gchar *exe_root;
|
2014-08-02 14:35:43 +02:00
|
|
|
|
|
|
|
hmodule = NULL;
|
2009-02-23 10:52:48 +01:00
|
|
|
if (address_of_function)
|
2005-04-08 14:03:16 +02:00
|
|
|
{
|
|
|
|
G_LOCK (g_utils_global);
|
2009-02-23 10:52:48 +01:00
|
|
|
hmodule = get_module_for_address (address_of_function);
|
2005-04-08 14:03:16 +02:00
|
|
|
if (hmodule != NULL)
|
|
|
|
{
|
|
|
|
if (per_module_data_dirs == NULL)
|
|
|
|
per_module_data_dirs = g_hash_table_new (NULL, NULL);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
retval = g_hash_table_lookup (per_module_data_dirs, hmodule);
|
|
|
|
|
|
|
|
if (retval != NULL)
|
|
|
|
{
|
|
|
|
G_UNLOCK (g_utils_global);
|
2011-03-13 03:50:45 +01:00
|
|
|
return (const gchar * const *) retval;
|
2005-04-08 14:03:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data_dirs = g_array_new (TRUE, TRUE, sizeof (char *));
|
|
|
|
|
|
|
|
/* Documents and Settings\All Users\Application Data */
|
|
|
|
p = get_special_folder (CSIDL_COMMON_APPDATA);
|
|
|
|
if (p)
|
|
|
|
g_array_append_val (data_dirs, p);
|
|
|
|
|
|
|
|
/* Documents and Settings\All Users\Documents */
|
|
|
|
p = get_special_folder (CSIDL_COMMON_DOCUMENTS);
|
|
|
|
if (p)
|
|
|
|
g_array_append_val (data_dirs, p);
|
|
|
|
|
|
|
|
/* Using the above subfolders of Documents and Settings perhaps
|
|
|
|
* makes sense from a Windows perspective.
|
|
|
|
*
|
|
|
|
* But looking at the actual use cases of this function in GTK+
|
|
|
|
* and GNOME software, what we really want is the "share"
|
|
|
|
* subdirectory of the installation directory for the package
|
|
|
|
* our caller is a part of.
|
|
|
|
*
|
2009-02-23 10:52:48 +01:00
|
|
|
* The address_of_function parameter, if non-NULL, points to a
|
|
|
|
* function in the calling module. Use that to determine that
|
|
|
|
* module's installation folder, and use its "share" subfolder.
|
2005-04-08 14:03:16 +02:00
|
|
|
*
|
|
|
|
* Additionally, also use the "share" subfolder of the installation
|
|
|
|
* locations of GLib and the .exe file being run.
|
|
|
|
*
|
|
|
|
* To guard against none of the above being what is really wanted,
|
|
|
|
* callers of this function should have Win32-specific code to look
|
|
|
|
* up their installation folder themselves, and handle a subfolder
|
|
|
|
* "share" of it in the same way as the folders returned from this
|
|
|
|
* function.
|
|
|
|
*/
|
|
|
|
|
2009-02-23 10:52:48 +01:00
|
|
|
p = get_module_share_dir (address_of_function);
|
2005-04-08 14:03:16 +02:00
|
|
|
if (p)
|
|
|
|
g_array_append_val (data_dirs, p);
|
|
|
|
|
2008-02-24 02:07:41 +01:00
|
|
|
if (glib_dll != NULL)
|
|
|
|
{
|
|
|
|
gchar *glib_root = g_win32_get_package_installation_directory_of_module (glib_dll);
|
|
|
|
p = g_build_filename (glib_root, "share", NULL);
|
|
|
|
if (p)
|
|
|
|
g_array_append_val (data_dirs, p);
|
|
|
|
g_free (glib_root);
|
|
|
|
}
|
2005-04-08 14:03:16 +02:00
|
|
|
|
2008-02-24 02:07:41 +01:00
|
|
|
exe_root = g_win32_get_package_installation_directory_of_module (NULL);
|
|
|
|
p = g_build_filename (exe_root, "share", NULL);
|
2005-04-08 14:03:16 +02:00
|
|
|
if (p)
|
|
|
|
g_array_append_val (data_dirs, p);
|
2008-02-24 02:07:41 +01:00
|
|
|
g_free (exe_root);
|
2005-04-08 14:03:16 +02:00
|
|
|
|
|
|
|
retval = (gchar **) g_array_free (data_dirs, FALSE);
|
|
|
|
|
2009-02-23 10:52:48 +01:00
|
|
|
if (address_of_function)
|
2005-04-08 14:03:16 +02:00
|
|
|
{
|
|
|
|
if (hmodule != NULL)
|
|
|
|
g_hash_table_insert (per_module_data_dirs, hmodule, retval);
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
}
|
|
|
|
|
2011-03-13 03:50:45 +01:00
|
|
|
return (const gchar * const *) retval;
|
2005-04-08 14:03:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2004-08-11 19:53:05 +02:00
|
|
|
/**
|
|
|
|
* g_get_system_data_dirs:
|
|
|
|
*
|
|
|
|
* Returns an ordered list of base directories in which to access
|
|
|
|
* system-wide application data.
|
|
|
|
*
|
2014-02-06 03:23:28 +01:00
|
|
|
* On UNIX platforms this is determined using the mechanisms described
|
|
|
|
* in the
|
|
|
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec)
|
2010-06-06 05:13:06 +02:00
|
|
|
* In this case the list of directories retrieved will be XDG_DATA_DIRS.
|
|
|
|
*
|
2005-04-08 14:03:16 +02:00
|
|
|
* On Windows the first elements in the list are the Application Data
|
|
|
|
* and Documents folders for All Users. (These can be determined only
|
|
|
|
* on Windows 2000 or later and are not present in the list on other
|
|
|
|
* Windows versions.) See documentation for CSIDL_COMMON_APPDATA and
|
|
|
|
* CSIDL_COMMON_DOCUMENTS.
|
|
|
|
*
|
|
|
|
* Then follows the "share" subfolder in the installation folder for
|
|
|
|
* the package containing the DLL that calls this function, if it can
|
|
|
|
* be determined.
|
|
|
|
*
|
|
|
|
* Finally the list contains the "share" subfolder in the installation
|
|
|
|
* folder for GLib, and in the installation folder for the package the
|
|
|
|
* application's .exe file belongs to.
|
|
|
|
*
|
|
|
|
* The installation folders above are determined by looking up the
|
|
|
|
* folder where the module (DLL or EXE) in question is located. If the
|
|
|
|
* folder's name is "bin", its parent is used, otherwise the folder
|
|
|
|
* itself.
|
|
|
|
*
|
|
|
|
* Note that on Windows the returned list can vary depending on where
|
|
|
|
* this function is called.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (array zero-terminated=1) (element-type filename) (transfer none):
|
|
|
|
* a %NULL-terminated array of strings owned by GLib that must not be
|
|
|
|
* modified or freed.
|
|
|
|
*
|
2004-08-11 19:53:05 +02:00
|
|
|
* Since: 2.6
|
|
|
|
**/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar * const *
|
2004-08-11 19:53:05 +02:00
|
|
|
g_get_system_data_dirs (void)
|
|
|
|
{
|
2005-04-08 14:03:16 +02:00
|
|
|
gchar **data_dir_vector;
|
2004-08-11 19:53:05 +02:00
|
|
|
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
|
|
|
if (!g_system_data_dirs)
|
|
|
|
{
|
2004-08-25 02:39:13 +02:00
|
|
|
#ifdef G_OS_WIN32
|
2005-04-08 14:03:16 +02:00
|
|
|
data_dir_vector = (gchar **) g_win32_get_system_data_dirs_for_module (NULL);
|
2004-08-25 02:39:13 +02:00
|
|
|
#else
|
2005-04-08 14:03:16 +02:00
|
|
|
gchar *data_dirs = (gchar *) g_getenv ("XDG_DATA_DIRS");
|
2004-08-11 19:53:05 +02:00
|
|
|
|
|
|
|
if (!data_dirs || !data_dirs[0])
|
|
|
|
data_dirs = "/usr/local/share/:/usr/share/";
|
2005-03-09 03:08:34 +01:00
|
|
|
|
2004-08-25 02:39:13 +02:00
|
|
|
data_dir_vector = g_strsplit (data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
|
2005-03-09 03:08:34 +01:00
|
|
|
#endif
|
2004-08-11 19:53:05 +02:00
|
|
|
|
|
|
|
g_system_data_dirs = data_dir_vector;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
data_dir_vector = g_system_data_dirs;
|
|
|
|
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
|
2011-03-13 03:50:45 +01:00
|
|
|
return (const gchar * const *) data_dir_vector;
|
2004-08-11 19:53:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_get_system_config_dirs:
|
|
|
|
*
|
|
|
|
* Returns an ordered list of base directories in which to access
|
|
|
|
* system-wide configuration information.
|
|
|
|
*
|
2014-02-06 03:23:28 +01:00
|
|
|
* On UNIX platforms this is determined using the mechanisms described
|
|
|
|
* in the
|
|
|
|
* [XDG Base Directory Specification](http://www.freedesktop.org/Standards/basedir-spec).
|
|
|
|
* In this case the list of directories retrieved will be `XDG_CONFIG_DIRS`.
|
2010-06-06 05:25:59 +02:00
|
|
|
*
|
|
|
|
* On Windows is the directory that contains application data for all users.
|
|
|
|
* A typical path is C:\Documents and Settings\All Users\Application Data.
|
|
|
|
* This folder is used for application data that is not user specific.
|
|
|
|
* For example, an application can store a spell-check dictionary, a database
|
|
|
|
* of clip art, or a log file in the CSIDL_COMMON_APPDATA folder.
|
|
|
|
* This information will not roam and is available to anyone using the computer.
|
|
|
|
*
|
2016-06-04 15:46:12 +02:00
|
|
|
* Returns: (array zero-terminated=1) (element-type filename) (transfer none):
|
|
|
|
* a %NULL-terminated array of strings owned by GLib that must not be
|
|
|
|
* modified or freed.
|
|
|
|
*
|
2004-08-11 19:53:05 +02:00
|
|
|
* Since: 2.6
|
|
|
|
**/
|
2011-03-13 03:50:45 +01:00
|
|
|
const gchar * const *
|
2004-08-11 19:53:05 +02:00
|
|
|
g_get_system_config_dirs (void)
|
|
|
|
{
|
|
|
|
gchar *conf_dirs, **conf_dir_vector;
|
|
|
|
|
|
|
|
G_LOCK (g_utils_global);
|
|
|
|
|
|
|
|
if (!g_system_config_dirs)
|
|
|
|
{
|
2004-08-25 02:39:13 +02:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
conf_dirs = get_special_folder (CSIDL_COMMON_APPDATA);
|
2005-03-09 03:08:34 +01:00
|
|
|
if (conf_dirs)
|
|
|
|
{
|
|
|
|
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
|
|
|
|
g_free (conf_dirs);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Return empty list */
|
|
|
|
conf_dir_vector = g_strsplit ("", G_SEARCHPATH_SEPARATOR_S, 0);
|
|
|
|
}
|
2004-08-25 02:39:13 +02:00
|
|
|
#else
|
2004-08-11 19:53:05 +02:00
|
|
|
conf_dirs = (gchar *) g_getenv ("XDG_CONFIG_DIRS");
|
|
|
|
|
|
|
|
if (!conf_dirs || !conf_dirs[0])
|
|
|
|
conf_dirs = "/etc/xdg";
|
2005-03-09 03:08:34 +01:00
|
|
|
|
2004-08-25 02:39:13 +02:00
|
|
|
conf_dir_vector = g_strsplit (conf_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
|
2005-03-09 03:08:34 +01:00
|
|
|
#endif
|
2004-12-02 15:27:31 +01:00
|
|
|
|
|
|
|
g_system_config_dirs = conf_dir_vector;
|
2004-08-11 19:53:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
conf_dir_vector = g_system_config_dirs;
|
|
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
|
2011-03-13 03:50:45 +01:00
|
|
|
return (const gchar * const *) conf_dir_vector;
|
2004-08-11 19:53:05 +02:00
|
|
|
}
|
|
|
|
|
2001-08-06 22:55:11 +02:00
|
|
|
/**
|
|
|
|
* g_nullify_pointer:
|
2013-12-06 13:23:09 +01:00
|
|
|
* @nullify_location: (not nullable): the memory address of the pointer.
|
2011-10-02 06:08:54 +02:00
|
|
|
*
|
2001-08-06 22:55:11 +02:00
|
|
|
* Set the pointer at the specified location to %NULL.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
g_nullify_pointer (gpointer *nullify_location)
|
|
|
|
{
|
|
|
|
g_return_if_fail (nullify_location != NULL);
|
|
|
|
|
|
|
|
*nullify_location = NULL;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:30:31 +02:00
|
|
|
#define KILOBYTE_FACTOR (G_GOFFSET_CONSTANT (1000))
|
|
|
|
#define MEGABYTE_FACTOR (KILOBYTE_FACTOR * KILOBYTE_FACTOR)
|
|
|
|
#define GIGABYTE_FACTOR (MEGABYTE_FACTOR * KILOBYTE_FACTOR)
|
|
|
|
#define TERABYTE_FACTOR (GIGABYTE_FACTOR * KILOBYTE_FACTOR)
|
|
|
|
#define PETABYTE_FACTOR (TERABYTE_FACTOR * KILOBYTE_FACTOR)
|
|
|
|
#define EXABYTE_FACTOR (PETABYTE_FACTOR * KILOBYTE_FACTOR)
|
|
|
|
|
|
|
|
#define KIBIBYTE_FACTOR (G_GOFFSET_CONSTANT (1024))
|
|
|
|
#define MEBIBYTE_FACTOR (KIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
|
|
|
#define GIBIBYTE_FACTOR (MEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
|
|
|
#define TEBIBYTE_FACTOR (GIBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
|
|
|
#define PEBIBYTE_FACTOR (TEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
|
|
|
#define EXBIBYTE_FACTOR (PEBIBYTE_FACTOR * KIBIBYTE_FACTOR)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* g_format_size:
|
|
|
|
* @size: a size in bytes
|
|
|
|
*
|
|
|
|
* Formats a size (for example the size of a file) into a human readable
|
|
|
|
* string. Sizes are rounded to the nearest size prefix (kB, MB, GB)
|
|
|
|
* and are displayed rounded to the nearest tenth. E.g. the file size
|
|
|
|
* 3292528 bytes will be converted into the string "3.2 MB".
|
|
|
|
*
|
|
|
|
* The prefix units base is 1000 (i.e. 1 kB is 1000 bytes).
|
|
|
|
*
|
|
|
|
* This string should be freed with g_free() when not needed any longer.
|
|
|
|
*
|
|
|
|
* See g_format_size_full() for more options about how the size might be
|
|
|
|
* formatted.
|
|
|
|
*
|
|
|
|
* Returns: a newly-allocated formatted string containing a human readable
|
|
|
|
* file size
|
|
|
|
*
|
|
|
|
* Since: 2.30
|
|
|
|
*/
|
|
|
|
gchar *
|
|
|
|
g_format_size (guint64 size)
|
|
|
|
{
|
|
|
|
return g_format_size_full (size, G_FORMAT_SIZE_DEFAULT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GFormatSizeFlags:
|
|
|
|
* @G_FORMAT_SIZE_DEFAULT: behave the same as g_format_size()
|
|
|
|
* @G_FORMAT_SIZE_LONG_FORMAT: include the exact number of bytes as part
|
|
|
|
* of the returned string. For example, "45.6 kB (45,612 bytes)".
|
|
|
|
* @G_FORMAT_SIZE_IEC_UNITS: use IEC (base 1024) units with "KiB"-style
|
|
|
|
* suffixes. IEC units should only be used for reporting things with
|
|
|
|
* a strong "power of 2" basis, like RAM sizes or RAID stripe sizes.
|
|
|
|
* Network and storage sizes should be reported in the normal SI units.
|
|
|
|
*
|
|
|
|
* Flags to modify the format of the string returned by g_format_size_full().
|
|
|
|
*/
|
|
|
|
|
2013-09-29 20:33:30 +02:00
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
|
|
|
|
2011-10-17 07:30:31 +02:00
|
|
|
/**
|
|
|
|
* g_format_size_full:
|
|
|
|
* @size: a size in bytes
|
|
|
|
* @flags: #GFormatSizeFlags to modify the output
|
|
|
|
*
|
|
|
|
* Formats a size.
|
|
|
|
*
|
|
|
|
* This function is similar to g_format_size() but allows for flags
|
|
|
|
* that modify the output. See #GFormatSizeFlags.
|
|
|
|
*
|
|
|
|
* Returns: a newly-allocated formatted string containing a human
|
|
|
|
* readable file size
|
|
|
|
*
|
|
|
|
* Since: 2.30
|
|
|
|
*/
|
|
|
|
gchar *
|
|
|
|
g_format_size_full (guint64 size,
|
|
|
|
GFormatSizeFlags flags)
|
|
|
|
{
|
|
|
|
GString *string;
|
|
|
|
|
|
|
|
string = g_string_new (NULL);
|
|
|
|
|
|
|
|
if (flags & G_FORMAT_SIZE_IEC_UNITS)
|
|
|
|
{
|
|
|
|
if (size < KIBIBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
g_string_printf (string,
|
|
|
|
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
|
|
|
(guint) size);
|
|
|
|
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (size < MEBIBYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f KiB"), (gdouble) size / (gdouble) KIBIBYTE_FACTOR);
|
|
|
|
else if (size < GIBIBYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f MiB"), (gdouble) size / (gdouble) MEBIBYTE_FACTOR);
|
|
|
|
|
|
|
|
else if (size < TEBIBYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f GiB"), (gdouble) size / (gdouble) GIBIBYTE_FACTOR);
|
|
|
|
|
|
|
|
else if (size < PEBIBYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f TiB"), (gdouble) size / (gdouble) TEBIBYTE_FACTOR);
|
|
|
|
|
|
|
|
else if (size < EXBIBYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f PiB"), (gdouble) size / (gdouble) PEBIBYTE_FACTOR);
|
|
|
|
|
|
|
|
else
|
|
|
|
g_string_printf (string, _("%.1f EiB"), (gdouble) size / (gdouble) EXBIBYTE_FACTOR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (size < KILOBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
g_string_printf (string,
|
|
|
|
g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes", (guint) size),
|
|
|
|
(guint) size);
|
|
|
|
flags &= ~G_FORMAT_SIZE_LONG_FORMAT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (size < MEGABYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f kB"), (gdouble) size / (gdouble) KILOBYTE_FACTOR);
|
|
|
|
|
|
|
|
else if (size < GIGABYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f MB"), (gdouble) size / (gdouble) MEGABYTE_FACTOR);
|
|
|
|
|
|
|
|
else if (size < TERABYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f GB"), (gdouble) size / (gdouble) GIGABYTE_FACTOR);
|
|
|
|
else if (size < PETABYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f TB"), (gdouble) size / (gdouble) TERABYTE_FACTOR);
|
|
|
|
|
|
|
|
else if (size < EXABYTE_FACTOR)
|
|
|
|
g_string_printf (string, _("%.1f PB"), (gdouble) size / (gdouble) PETABYTE_FACTOR);
|
|
|
|
|
|
|
|
else
|
|
|
|
g_string_printf (string, _("%.1f EB"), (gdouble) size / (gdouble) EXABYTE_FACTOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & G_FORMAT_SIZE_LONG_FORMAT)
|
|
|
|
{
|
|
|
|
/* First problem: we need to use the number of bytes to decide on
|
|
|
|
* the plural form that is used for display, but the number of
|
|
|
|
* bytes potentially exceeds the size of a guint (which is what
|
|
|
|
* ngettext() takes).
|
|
|
|
*
|
|
|
|
* From a pragmatic standpoint, it seems that all known languages
|
|
|
|
* base plural forms on one or both of the following:
|
|
|
|
*
|
|
|
|
* - the lowest digits of the number
|
|
|
|
*
|
|
|
|
* - if the number if greater than some small value
|
|
|
|
*
|
|
|
|
* Here's how we fake it: Draw an arbitrary line at one thousand.
|
|
|
|
* If the number is below that, then fine. If it is above it,
|
|
|
|
* then we take the modulus of the number by one thousand (in
|
|
|
|
* order to keep the lowest digits) and add one thousand to that
|
|
|
|
* (in order to ensure that 1001 is not treated the same as 1).
|
|
|
|
*/
|
|
|
|
guint plural_form = size < 1000 ? size : size % 1000 + 1000;
|
|
|
|
|
|
|
|
/* Second problem: we need to translate the string "%u byte" and
|
|
|
|
* "%u bytes" for pluralisation, but the correct number format to
|
|
|
|
* use for a gsize is different depending on which architecture
|
|
|
|
* we're on.
|
|
|
|
*
|
|
|
|
* Solution: format the number separately and use "%s bytes" on
|
|
|
|
* all platforms.
|
|
|
|
*/
|
|
|
|
const gchar *translated_format;
|
|
|
|
gchar *formatted_number;
|
|
|
|
|
|
|
|
/* Translators: the %s in "%s bytes" will always be replaced by a number. */
|
|
|
|
translated_format = g_dngettext(GETTEXT_PACKAGE, "%s byte", "%s bytes", plural_form);
|
|
|
|
/* XXX: Windows doesn't support the "'" format modifier, so we
|
|
|
|
* must not use it there. Instead, just display the number
|
|
|
|
* without separation. Bug #655336 is open until a solution is
|
|
|
|
* found.
|
|
|
|
*/
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
formatted_number = g_strdup_printf ("%'"G_GUINT64_FORMAT, size);
|
|
|
|
#else
|
|
|
|
formatted_number = g_strdup_printf ("%"G_GUINT64_FORMAT, size);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
g_string_append (string, " (");
|
|
|
|
g_string_append_printf (string, translated_format, formatted_number);
|
|
|
|
g_free (formatted_number);
|
|
|
|
g_string_append (string, ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
return g_string_free (string, FALSE);
|
|
|
|
}
|
|
|
|
|
2013-09-29 20:33:30 +02:00
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
|
2011-10-17 07:30:31 +02:00
|
|
|
/**
|
|
|
|
* g_format_size_for_display:
|
|
|
|
* @size: a size in bytes
|
|
|
|
*
|
|
|
|
* Formats a size (for example the size of a file) into a human
|
|
|
|
* readable string. Sizes are rounded to the nearest size prefix
|
|
|
|
* (KB, MB, GB) and are displayed rounded to the nearest tenth.
|
|
|
|
* E.g. the file size 3292528 bytes will be converted into the
|
|
|
|
* string "3.1 MB".
|
|
|
|
*
|
|
|
|
* The prefix units base is 1024 (i.e. 1 KB is 1024 bytes).
|
|
|
|
*
|
|
|
|
* This string should be freed with g_free() when not needed any longer.
|
|
|
|
*
|
|
|
|
* Returns: a newly-allocated formatted string containing a human
|
|
|
|
* readable file size
|
|
|
|
*
|
|
|
|
* Since: 2.16
|
|
|
|
*
|
|
|
|
* Deprecated:2.30: This function is broken due to its use of SI
|
|
|
|
* suffixes to denote IEC units. Use g_format_size() instead.
|
|
|
|
*/
|
|
|
|
gchar *
|
|
|
|
g_format_size_for_display (goffset size)
|
|
|
|
{
|
|
|
|
if (size < (goffset) KIBIBYTE_FACTOR)
|
|
|
|
return g_strdup_printf (g_dngettext(GETTEXT_PACKAGE, "%u byte", "%u bytes",(guint) size), (guint) size);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gdouble displayed_size;
|
|
|
|
|
|
|
|
if (size < (goffset) MEBIBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
displayed_size = (gdouble) size / (gdouble) KIBIBYTE_FACTOR;
|
2012-11-05 14:24:30 +01:00
|
|
|
/* Translators: this is from the deprecated function g_format_size_for_display() which uses 'KB' to
|
|
|
|
* mean 1024 bytes. I am aware that 'KB' is not correct, but it has been preserved for reasons of
|
|
|
|
* compatibility. Users will not see this string unless a program is using this deprecated function.
|
|
|
|
* Please translate as literally as possible.
|
|
|
|
*/
|
2011-10-17 07:30:31 +02:00
|
|
|
return g_strdup_printf (_("%.1f KB"), displayed_size);
|
|
|
|
}
|
|
|
|
else if (size < (goffset) GIBIBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
displayed_size = (gdouble) size / (gdouble) MEBIBYTE_FACTOR;
|
|
|
|
return g_strdup_printf (_("%.1f MB"), displayed_size);
|
|
|
|
}
|
|
|
|
else if (size < (goffset) TEBIBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
displayed_size = (gdouble) size / (gdouble) GIBIBYTE_FACTOR;
|
|
|
|
return g_strdup_printf (_("%.1f GB"), displayed_size);
|
|
|
|
}
|
|
|
|
else if (size < (goffset) PEBIBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
displayed_size = (gdouble) size / (gdouble) TEBIBYTE_FACTOR;
|
|
|
|
return g_strdup_printf (_("%.1f TB"), displayed_size);
|
|
|
|
}
|
|
|
|
else if (size < (goffset) EXBIBYTE_FACTOR)
|
|
|
|
{
|
|
|
|
displayed_size = (gdouble) size / (gdouble) PEBIBYTE_FACTOR;
|
|
|
|
return g_strdup_printf (_("%.1f PB"), displayed_size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
displayed_size = (gdouble) size / (gdouble) EXBIBYTE_FACTOR;
|
|
|
|
return g_strdup_printf (_("%.1f EB"), displayed_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-27 19:15:16 +02:00
|
|
|
#if defined (G_OS_WIN32) && !defined (_WIN64)
|
2005-01-01 03:09:51 +01:00
|
|
|
|
|
|
|
/* Binary compatibility versions. Not for newly compiled code. */
|
|
|
|
|
2013-02-04 14:04:05 +01:00
|
|
|
_GLIB_EXTERN const gchar *g_get_user_name_utf8 (void);
|
|
|
|
_GLIB_EXTERN const gchar *g_get_real_name_utf8 (void);
|
|
|
|
_GLIB_EXTERN const gchar *g_get_home_dir_utf8 (void);
|
|
|
|
_GLIB_EXTERN const gchar *g_get_tmp_dir_utf8 (void);
|
|
|
|
_GLIB_EXTERN gchar *g_find_program_in_path_utf8 (const gchar *program);
|
2005-01-01 03:09:51 +01:00
|
|
|
|
2013-02-04 14:04:05 +01:00
|
|
|
gchar *
|
|
|
|
g_find_program_in_path_utf8 (const gchar *program)
|
2005-01-01 03:09:51 +01:00
|
|
|
{
|
2013-02-04 14:04:05 +01:00
|
|
|
return g_find_program_in_path (program);
|
2005-01-01 03:09:51 +01:00
|
|
|
}
|
|
|
|
|
2013-02-04 14:04:05 +01:00
|
|
|
const gchar *g_get_user_name_utf8 (void) { return g_get_user_name (); }
|
|
|
|
const gchar *g_get_real_name_utf8 (void) { return g_get_real_name (); }
|
|
|
|
const gchar *g_get_home_dir_utf8 (void) { return g_get_home_dir (); }
|
|
|
|
const gchar *g_get_tmp_dir_utf8 (void) { return g_get_tmp_dir (); }
|
2005-01-01 03:09:51 +01:00
|
|
|
|
|
|
|
#endif
|
CVE-2012-3524: Hardening for being run in a setuid environment
Some programs attempt to use libglib (or even libgio) when setuid.
For a long time, GTK+ simply aborted if launched in this
configuration, but we never had a real policy for GLib.
I'm not sure whether we should advertise such support. However, given
that there are real-world programs that do this currently, we can make
them safer with not too much effort.
Better to fix a problem caused by an interaction between two
components in *both* places if possible.
This patch adds a private function g_check_setuid() which is used to
first ensure we don't run an external dbus-launch binary if
DBUS_SESSION_BUS_ADDRESS isn't set.
Second, we also ensure the local VFS is used in this case. The
gdaemonvfs extension point will end up talking to the session bus
which is typically undesirable in a setuid context.
Implementing g_check_setuid() is interesting - whether or not we're
running in a privilege-escalated path is operating system specific.
Note that GTK+'s code to check euid versus uid worked historically on
Unix, more modern systems have filesystem capabilities and SELinux
domain transitions, neither of which are captured by the uid
comparison.
On Linux/glibc, the way this works is that the kernel sets an
AT_SECURE flag in the ELF auxiliary vector, and glibc looks for it on
startup. If found, then glibc sets a public-but-undocumented
__libc_enable_secure variable which we can use. Unfortunately, while
it *previously* worked to check this variable, a combination of newer
binutils and RPM break it:
http://www.openwall.com/lists/owl-dev/2012/08/14/1
So for now on Linux/glibc, we fall back to the historical Unix version
until we get glibc fixed.
On some BSD variants, there is a issetugid() function. On other Unix
variants, we fall back to what GTK+ has been doing.
Reported-By: Sebastian Krahmer <krahmer@suse.de>
Signed-off-by: Colin Walters <walters@verbum.org>
2012-08-22 20:26:11 +02:00
|
|
|
|
|
|
|
/* Private API:
|
|
|
|
*
|
|
|
|
* Returns %TRUE if the current process was executed as setuid (or an
|
|
|
|
* equivalent __libc_enable_secure is available). See:
|
|
|
|
* http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html
|
|
|
|
*/
|
2013-01-18 19:27:16 +01:00
|
|
|
gboolean
|
CVE-2012-3524: Hardening for being run in a setuid environment
Some programs attempt to use libglib (or even libgio) when setuid.
For a long time, GTK+ simply aborted if launched in this
configuration, but we never had a real policy for GLib.
I'm not sure whether we should advertise such support. However, given
that there are real-world programs that do this currently, we can make
them safer with not too much effort.
Better to fix a problem caused by an interaction between two
components in *both* places if possible.
This patch adds a private function g_check_setuid() which is used to
first ensure we don't run an external dbus-launch binary if
DBUS_SESSION_BUS_ADDRESS isn't set.
Second, we also ensure the local VFS is used in this case. The
gdaemonvfs extension point will end up talking to the session bus
which is typically undesirable in a setuid context.
Implementing g_check_setuid() is interesting - whether or not we're
running in a privilege-escalated path is operating system specific.
Note that GTK+'s code to check euid versus uid worked historically on
Unix, more modern systems have filesystem capabilities and SELinux
domain transitions, neither of which are captured by the uid
comparison.
On Linux/glibc, the way this works is that the kernel sets an
AT_SECURE flag in the ELF auxiliary vector, and glibc looks for it on
startup. If found, then glibc sets a public-but-undocumented
__libc_enable_secure variable which we can use. Unfortunately, while
it *previously* worked to check this variable, a combination of newer
binutils and RPM break it:
http://www.openwall.com/lists/owl-dev/2012/08/14/1
So for now on Linux/glibc, we fall back to the historical Unix version
until we get glibc fixed.
On some BSD variants, there is a issetugid() function. On other Unix
variants, we fall back to what GTK+ has been doing.
Reported-By: Sebastian Krahmer <krahmer@suse.de>
Signed-off-by: Colin Walters <walters@verbum.org>
2012-08-22 20:26:11 +02:00
|
|
|
g_check_setuid (void)
|
|
|
|
{
|
|
|
|
/* TODO: get __libc_enable_secure exported from glibc.
|
|
|
|
* See http://www.openwall.com/lists/owl-dev/2012/08/14/1
|
|
|
|
*/
|
|
|
|
#if 0 && defined(HAVE_LIBC_ENABLE_SECURE)
|
|
|
|
{
|
|
|
|
/* See glibc/include/unistd.h */
|
|
|
|
extern int __libc_enable_secure;
|
|
|
|
return __libc_enable_secure;
|
|
|
|
}
|
2014-09-09 20:18:20 +02:00
|
|
|
#elif defined(HAVE_ISSETUGID) && !defined(__BIONIC__)
|
CVE-2012-3524: Hardening for being run in a setuid environment
Some programs attempt to use libglib (or even libgio) when setuid.
For a long time, GTK+ simply aborted if launched in this
configuration, but we never had a real policy for GLib.
I'm not sure whether we should advertise such support. However, given
that there are real-world programs that do this currently, we can make
them safer with not too much effort.
Better to fix a problem caused by an interaction between two
components in *both* places if possible.
This patch adds a private function g_check_setuid() which is used to
first ensure we don't run an external dbus-launch binary if
DBUS_SESSION_BUS_ADDRESS isn't set.
Second, we also ensure the local VFS is used in this case. The
gdaemonvfs extension point will end up talking to the session bus
which is typically undesirable in a setuid context.
Implementing g_check_setuid() is interesting - whether or not we're
running in a privilege-escalated path is operating system specific.
Note that GTK+'s code to check euid versus uid worked historically on
Unix, more modern systems have filesystem capabilities and SELinux
domain transitions, neither of which are captured by the uid
comparison.
On Linux/glibc, the way this works is that the kernel sets an
AT_SECURE flag in the ELF auxiliary vector, and glibc looks for it on
startup. If found, then glibc sets a public-but-undocumented
__libc_enable_secure variable which we can use. Unfortunately, while
it *previously* worked to check this variable, a combination of newer
binutils and RPM break it:
http://www.openwall.com/lists/owl-dev/2012/08/14/1
So for now on Linux/glibc, we fall back to the historical Unix version
until we get glibc fixed.
On some BSD variants, there is a issetugid() function. On other Unix
variants, we fall back to what GTK+ has been doing.
Reported-By: Sebastian Krahmer <krahmer@suse.de>
Signed-off-by: Colin Walters <walters@verbum.org>
2012-08-22 20:26:11 +02:00
|
|
|
/* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */
|
2014-09-09 20:18:20 +02:00
|
|
|
|
|
|
|
/* Android had it in older versions but the new 64 bit ABI does not
|
|
|
|
* have it anymore, and some versions of the 32 bit ABI neither.
|
|
|
|
* https://code.google.com/p/android-developer-preview/issues/detail?id=168
|
|
|
|
*/
|
CVE-2012-3524: Hardening for being run in a setuid environment
Some programs attempt to use libglib (or even libgio) when setuid.
For a long time, GTK+ simply aborted if launched in this
configuration, but we never had a real policy for GLib.
I'm not sure whether we should advertise such support. However, given
that there are real-world programs that do this currently, we can make
them safer with not too much effort.
Better to fix a problem caused by an interaction between two
components in *both* places if possible.
This patch adds a private function g_check_setuid() which is used to
first ensure we don't run an external dbus-launch binary if
DBUS_SESSION_BUS_ADDRESS isn't set.
Second, we also ensure the local VFS is used in this case. The
gdaemonvfs extension point will end up talking to the session bus
which is typically undesirable in a setuid context.
Implementing g_check_setuid() is interesting - whether or not we're
running in a privilege-escalated path is operating system specific.
Note that GTK+'s code to check euid versus uid worked historically on
Unix, more modern systems have filesystem capabilities and SELinux
domain transitions, neither of which are captured by the uid
comparison.
On Linux/glibc, the way this works is that the kernel sets an
AT_SECURE flag in the ELF auxiliary vector, and glibc looks for it on
startup. If found, then glibc sets a public-but-undocumented
__libc_enable_secure variable which we can use. Unfortunately, while
it *previously* worked to check this variable, a combination of newer
binutils and RPM break it:
http://www.openwall.com/lists/owl-dev/2012/08/14/1
So for now on Linux/glibc, we fall back to the historical Unix version
until we get glibc fixed.
On some BSD variants, there is a issetugid() function. On other Unix
variants, we fall back to what GTK+ has been doing.
Reported-By: Sebastian Krahmer <krahmer@suse.de>
Signed-off-by: Colin Walters <walters@verbum.org>
2012-08-22 20:26:11 +02:00
|
|
|
return issetugid ();
|
|
|
|
#elif defined(G_OS_UNIX)
|
|
|
|
uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
|
|
|
|
gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
|
|
|
|
|
|
|
|
static gsize check_setuid_initialised;
|
|
|
|
static gboolean is_setuid;
|
|
|
|
|
|
|
|
if (g_once_init_enter (&check_setuid_initialised))
|
|
|
|
{
|
|
|
|
#ifdef HAVE_GETRESUID
|
|
|
|
/* These aren't in the header files, so we prototype them here.
|
|
|
|
*/
|
|
|
|
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
|
|
|
|
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
|
|
|
|
|
|
|
|
if (getresuid (&ruid, &euid, &suid) != 0 ||
|
|
|
|
getresgid (&rgid, &egid, &sgid) != 0)
|
|
|
|
#endif /* HAVE_GETRESUID */
|
|
|
|
{
|
|
|
|
suid = ruid = getuid ();
|
|
|
|
sgid = rgid = getgid ();
|
|
|
|
euid = geteuid ();
|
|
|
|
egid = getegid ();
|
|
|
|
}
|
|
|
|
|
|
|
|
is_setuid = (ruid != euid || ruid != suid ||
|
|
|
|
rgid != egid || rgid != sgid);
|
|
|
|
|
|
|
|
g_once_init_leave (&check_setuid_initialised, 1);
|
|
|
|
}
|
|
|
|
return is_setuid;
|
|
|
|
#else
|
|
|
|
return FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
2016-03-30 15:56:43 +02:00
|
|
|
|
2016-04-27 15:53:33 +02:00
|
|
|
#ifdef G_OS_WIN32
|
2016-03-30 15:56:43 +02:00
|
|
|
/**
|
|
|
|
* g_abort:
|
|
|
|
*
|
|
|
|
* A wrapper for the POSIX abort() function.
|
|
|
|
*
|
|
|
|
* On Windows it is a function that makes extra effort (including a call
|
|
|
|
* to abort()) to ensure that a debugger-catchable exception is thrown
|
|
|
|
* before the program terminates.
|
|
|
|
*
|
|
|
|
* See your C library manual for more details about abort().
|
|
|
|
*
|
|
|
|
* Since: 2.50
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
g_abort (void)
|
|
|
|
{
|
|
|
|
/* One call to break the debugger */
|
|
|
|
DebugBreak ();
|
|
|
|
/* One call in case CRT does get saner about abort() behaviour */
|
|
|
|
abort ();
|
|
|
|
/* And one call to bind them all and terminate the program for sure */
|
|
|
|
ExitProcess (127);
|
|
|
|
}
|
2016-04-27 15:53:33 +02:00
|
|
|
#endif
|