Gimp/libgimp/gimpenv.c
Tor Lillqvist 2e661c1c1e app/gimprc.c (parse_gimprc_file) Make sure the directory doesn't get
2000-10-28  Tor Lillqvist  <tml@iki.fi>

	* app/gimprc.c (parse_gimprc_file)
	* libgimp/gimpenv.c (gimp_directory): Make sure the directory
	doesn't get double path separators in case HOME ends with one. On
	Windows, if the user has set his HOME to \, we get into trouble
	when we try to access a path like \\_gimp1.1\gimprc. Windows
	thinks it's an UNC path to a network server called "_gimp1.1", and
	the program hangs for a moment.
2000-10-28 17:23:39 +00:00

560 lines
13 KiB
C

/* LIBGIMP - The GIMP Library
*
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1999 Tor Lillqvist
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <glib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "gimpenv.h"
#ifdef G_OS_WIN32
#define STRICT
#include <windows.h> /* For GetModuleFileName */
#include <io.h>
#ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
#endif
#ifndef S_IWGRP
#define S_IWGRP (_S_IWRITE>>3)
#define S_IWOTH (_S_IWRITE>>6)
#endif
#ifndef S_ISDIR
# define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
# define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
#endif
#define uid_t gint
#define gid_t gint
#define geteuid() 0
#define getegid() 0
#endif
#ifdef __EMX__
extern const char *__XOS2RedirRoot(const char *);
#endif
/**
* gimp_directory:
*
* Returns the user-specific GIMP settings directory. If the environment
* variable GIMP_DIRECTORY exists, it is used. If it is an absolute path,
* it is used as is. If it is a relative path, it is taken to be a
* subdirectory of the home directory. If it is relative path, and no home
* directory can be determined, it is taken to be a subdirectory of
* gimp_data_directory().
*
* The usual case is that no GIMP_DIRECTORY environment variable exists,
* and then we use the GIMPDIR subdirectory of the home directory. If no
* home directory exists, we use a per-user subdirectory of
* gimp_data_directory().
* In any case, we always return some non-empty string, whether it
* corresponds to an existing directory or not.
*
* The returned string is allocated just once, and should *NOT* be
* freed with g_free().
*
* Returns: The user-specific GIMP settings directory.
*/
gchar*
gimp_directory (void)
{
static gchar *gimp_dir = NULL;
gchar *env_gimp_dir;
gchar *home_dir;
gchar *home_dir_sep;
if (gimp_dir != NULL)
return gimp_dir;
env_gimp_dir = g_getenv ("GIMP_DIRECTORY");
home_dir = g_get_home_dir ();
if (home_dir != NULL && home_dir[strlen (home_dir)-1] != G_DIR_SEPARATOR)
home_dir_sep = G_DIR_SEPARATOR_S;
else
home_dir_sep = "";
if (NULL != env_gimp_dir)
{
if (g_path_is_absolute (env_gimp_dir))
gimp_dir = g_strdup (env_gimp_dir);
else
{
if (NULL != home_dir)
{
gimp_dir = g_strconcat (home_dir,
home_dir_sep,
env_gimp_dir,
NULL);
}
else
{
gimp_dir = g_strconcat (gimp_data_directory (),
G_DIR_SEPARATOR_S,
env_gimp_dir,
NULL);
}
}
}
else
{
#ifdef __EMX__
gimp_dir = g_strdup(__XOS2RedirRoot(GIMPDIR));
return gimp_dir;
#endif
if (NULL != home_dir)
{
gimp_dir = g_strconcat (home_dir,
home_dir_sep,
GIMPDIR,
NULL);
}
else
{
#ifndef G_OS_WIN32
g_message ("warning: no home directory.");
#endif
gimp_dir = g_strconcat (gimp_data_directory (),
G_DIR_SEPARATOR_S,
GIMPDIR,
".",
g_get_user_name (),
NULL);
}
}
return gimp_dir;
}
/**
* gimp_personal_rc_file:
* @basename: The basename of a rc_file.
*
* Returns the name of a file in the user-specific GIMP settings directory.
*
* The returned string is allocated dynamically and *SHOULD* be freed
* with g_free() after use.
*
* Returns: The name of a file in the user-specific GIMP settings directory.
*/
gchar*
gimp_personal_rc_file (gchar *basename)
{
return g_strconcat (gimp_directory (),
G_DIR_SEPARATOR_S,
basename,
NULL);
}
/**
* gimp_data_directory:
*
* Returns the top directory for GIMP data. If the environment variable
* GIMP_DATADIR exists, that is used. It should be an absolute pathname.
* Otherwise, on Unix the compile-time defined directory is used. On
* Win32, the installation directory as deduced from the executable's
* name is used.
*
* The returned string is allocated just once, and should *NOT* be
* freed with g_free().
*
* Returns: The top directory for GIMP data.
*/
gchar*
gimp_data_directory (void)
{
static gchar *gimp_data_dir = NULL;
gchar *env_gimp_data_dir = NULL;
if (gimp_data_dir != NULL)
return gimp_data_dir;
env_gimp_data_dir = g_getenv ("GIMP_DATADIR");
if (NULL != env_gimp_data_dir)
{
if (!g_path_is_absolute (env_gimp_data_dir))
g_error ("GIMP_DATADIR environment variable should be an absolute path.");
#ifndef __EMX__
gimp_data_dir = g_strdup (env_gimp_data_dir);
#else
gimp_data_dir = g_strdup (__XOS2RedirRoot(env_gimp_data_dir));
#endif
}
else
{
#ifndef G_OS_WIN32
#ifndef __EMX__
gimp_data_dir = DATADIR;
#else
gimp_data_dir = g_strdup(__XOS2RedirRoot(DATADIR));
#endif
#else
/* Figure it out from the executable name */
gchar filename[MAX_PATH];
gchar *sep1, *sep2;
if (GetModuleFileName (NULL, filename, sizeof (filename)) == 0)
g_error ("GetModuleFilename failed\n");
/* If the executable file name is of the format
* <foobar>\bin\gimp.exe of <foobar>\plug-ins\filter.exe, * use
* <foobar>. Otherwise, use the directory where the executable
* is.
*/
sep1 = strrchr (filename, G_DIR_SEPARATOR);
*sep1 = '\0';
sep2 = strrchr (filename, G_DIR_SEPARATOR);
if (sep2 != NULL)
{
if (g_strcasecmp (sep2 + 1, "bin") == 0
|| g_strcasecmp (sep2 + 1, "plug-ins") == 0)
*sep2 = '\0';
}
gimp_data_dir = g_strdup (filename);
#endif
}
return gimp_data_dir;
}
/**
* gimp_sysconf_directory:
*
* Returns the top directory for GIMP config files. If the environment
* variable GIMP_SYSCONFDIR exists, that is used. It should be an
* absolute pathname. Otherwise, on Unix the compile-time defined
* directory is used. On Win32, the installation directory as deduced
* from the executable's name is used.
*
* The returned string is allocated just once, and should *NOT* be
* freed with g_free().
*
* Returns: The top directory for GIMP config files. */
gchar*
gimp_sysconf_directory (void)
{
static gchar *gimp_sysconf_dir = NULL;
gchar *env_gimp_sysconf_dir = NULL;
if (gimp_sysconf_dir != NULL)
return gimp_sysconf_dir;
env_gimp_sysconf_dir = g_getenv ("GIMP_SYSCONFDIR");
if (NULL != env_gimp_sysconf_dir)
{
if (!g_path_is_absolute (env_gimp_sysconf_dir))
g_error ("GIMP_SYSCONFDIR environment variable should be an absolute path.");
#ifndef __EMX__
gimp_sysconf_dir = g_strdup (env_gimp_sysconf_dir);
#else
gimp_sysconf_dir = g_strdup (__XOS2RedirRoot(env_gimp_sysconf_dir));
#endif
}
else
{
#ifndef G_OS_WIN32
#ifndef __EMX__
gimp_sysconf_dir = SYSCONFDIR;
#else
gimp_sysconf_dir = g_strdup(__XOS2RedirRoot(SYSCONFDIR));
#endif
#else
/* Figure it out from the executable name */
gchar filename[MAX_PATH];
gchar *sep1, *sep2;
if (GetModuleFileName (NULL, filename, sizeof (filename)) == 0)
g_error ("GetModuleFilename failed\n");
/* If the executable file name is of the format
* <foobar>\bin\gimp.exe of <foobar>\plug-ins\filter.exe, * use
* <foobar>. Otherwise, use the directory where the executable
* is.
*/
sep1 = strrchr (filename, G_DIR_SEPARATOR);
*sep1 = '\0';
sep2 = strrchr (filename, G_DIR_SEPARATOR);
if (sep2 != NULL)
{
if (g_strcasecmp (sep2 + 1, "bin") == 0
|| g_strcasecmp (sep2 + 1, "plug-ins") == 0)
*sep2 = '\0';
}
gimp_sysconf_dir = g_strdup (filename);
#endif
}
return gimp_sysconf_dir;
}
/**
* gimp_gtkrc:
*
* Returns the name of the GIMP's application-specific gtkrc file.
*
* The returned string is allocated just once, and should *NOT* be
* freed with g_free().
*
* Returns: The name of the GIMP's application-specific gtkrc file.
*/
gchar*
gimp_gtkrc (void)
{
static gchar *gimp_gtkrc_filename = NULL;
if (gimp_gtkrc_filename != NULL)
return gimp_gtkrc_filename;
gimp_gtkrc_filename = g_strconcat (gimp_sysconf_directory (),
G_DIR_SEPARATOR_S,
"gtkrc",
NULL);
return gimp_gtkrc_filename;
}
/**
* gimp_path_parse:
* @path: A list of directories separated by #G_SEARCHPATH_SEPARATOR.
* @max_paths: The maximum number of directories to return.
* @check: #TRUE if you want the directories to be checked.
* @check_failed: Returns a #GList of path elements for which the
* check failed. Each list element is guaranteed
* to end with a #G_PATH_SEPARATOR.
*
* Returns: A #GList of all directories in @path. Each list element
* is guaranteed to end with a #G_PATH_SEPARATOR.
*/
GList *
gimp_path_parse (gchar *path,
gint max_paths,
gboolean check,
GList **check_failed)
{
gchar *home;
gchar **patharray;
GList *list = NULL;
GList *fail_list = NULL;
gint i;
struct stat filestat;
gint err = FALSE;
if (!path || !*path || max_paths < 1 || max_paths > 256)
return NULL;
home = g_get_home_dir ();
patharray = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, max_paths);
for (i = 0; i < max_paths; i++)
{
GString *dir;
if (!patharray[i])
break;
#ifndef G_OS_WIN32
if (*patharray[i] == '~')
{
dir = g_string_new (home);
g_string_append (dir, patharray[i] + 1);
}
else
#endif
{
dir = g_string_new (patharray[i]);
}
#ifdef __EMX__
_fnslashify (dir);
#endif
if (check)
{
/* check if directory exists */
err = stat (dir->str, &filestat);
if (!err && S_ISDIR (filestat.st_mode))
{
if (dir->str[dir->len - 1] != G_DIR_SEPARATOR)
g_string_append_c (dir, G_DIR_SEPARATOR);
}
}
if (!err)
list = g_list_prepend (list, g_strdup (dir->str));
else if (check_failed)
fail_list = g_list_prepend (fail_list, g_strdup (dir->str));
g_string_free (dir, TRUE);
}
g_strfreev (patharray);
list = g_list_reverse (list);
if (check && check_failed)
{
fail_list = g_list_reverse (fail_list);
*check_failed = fail_list;
}
return list;
}
/**
* gimp_path_to_str:
* @path: A list of directories as returned by gimp_path_parse().
*
* Returns: A searchpath string separated by #G_SEARCHPATH_SEPARATOR.
*
*/
gchar *
gimp_path_to_str (GList *path)
{
GString *str = NULL;
GList *list;
gchar *retval = NULL;
for (list = path; list; list = g_list_next (list))
{
if (str)
{
g_string_append_c (str, G_SEARCHPATH_SEPARATOR);
g_string_append (str, (gchar *) list->data);
}
else
{
str = g_string_new ((gchar *) list->data);
}
}
if (str)
{
retval = str->str;
g_string_free (str, FALSE);
}
return retval;
}
/**
* gimp_path_free:
* @path: A list of directories as returned by gimp_path_parse().
*
* This function frees the memory allocated for the list and it's strings.
*
*/
void
gimp_path_free (GList *path)
{
GList *list;
if (path)
{
for (list = path; list; list = g_list_next (list))
{
g_free (list->data);
}
g_list_free (path);
}
}
/**
* gimp_path_get_user_writable_dir:
* @path: A list of directories as returned by gimp_path_parse().
*
* Note that you have to g_free() the returned string.
*
* Returns: The first directory in @path where the user has write permission.
*
*/
gchar *
gimp_path_get_user_writable_dir (GList *path)
{
GList *list;
uid_t euid;
gid_t egid;
struct stat filestat;
gint err;
euid = geteuid ();
egid = getegid ();
for (list = path; list; list = g_list_next (list))
{
/* check if directory exists */
/* ugly hack to handle paths with an extra G_DIR_SEPARATOR
* attached. The stat() in MSVCRT doesn't like that.
*/
gchar *dir = g_strdup ((gchar *) list->data);
gchar *p = dir;
gint pl;
if (g_path_is_absolute (dir))
p = g_path_skip_root (dir);
pl = strlen (p);
if (pl > 0 && p[pl-1] == G_DIR_SEPARATOR)
p[pl-1] = '\0';
err = stat (dir, &filestat);
g_free (dir);
/* this is tricky:
* if a file is e.g. owned by the current user but not user-writable,
* the user has no permission to write to the file regardless
* of his group's or other's write permissions
*/
if (!err && S_ISDIR (filestat.st_mode) &&
((filestat.st_mode & S_IWUSR) ||
((filestat.st_mode & S_IWGRP) &&
(euid != filestat.st_uid)) ||
((filestat.st_mode & S_IWOTH) &&
(euid != filestat.st_uid) &&
(egid != filestat.st_gid))))
{
return g_strdup ((gchar *) list->data);
}
}
return NULL;
}