/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimp-user-install.c * Copyright (C) 2000-2006 Michael Natterer and Sven Neumann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #ifdef G_OS_WIN32 #include #endif #include "libgimpbase/gimpbase.h" #include "core-types.h" #include "config/gimpconfig-file.h" #include "gimp-templates.h" #include "gimp-user-install.h" #include "gimp-intl.h" struct _GimpUserInstall { gboolean verbose; gchar *old_dir; gint old_major; gint old_minor; const gchar *migrate; GimpUserInstallLogFunc log; gpointer log_data; }; typedef enum { USER_INSTALL_MKDIR, /* Create the directory */ USER_INSTALL_COPY /* Copy from sysconf directory */ } GimpUserInstallAction; static const struct { const gchar *name; GimpUserInstallAction action; } gimp_user_install_items[] = { { "gtkrc", USER_INSTALL_COPY }, { "brushes", USER_INSTALL_MKDIR }, { "fonts", USER_INSTALL_MKDIR }, { "gradients", USER_INSTALL_MKDIR }, { "palettes", USER_INSTALL_MKDIR }, { "patterns", USER_INSTALL_MKDIR }, { "plug-ins", USER_INSTALL_MKDIR }, { "modules", USER_INSTALL_MKDIR }, { "interpreters", USER_INSTALL_MKDIR }, { "environ", USER_INSTALL_MKDIR }, { "scripts", USER_INSTALL_MKDIR }, { "templates", USER_INSTALL_MKDIR }, { "themes", USER_INSTALL_MKDIR }, { "tmp", USER_INSTALL_MKDIR }, { "tool-options", USER_INSTALL_MKDIR }, { "curves", USER_INSTALL_MKDIR }, { "levels", USER_INSTALL_MKDIR }, { "fractalexplorer", USER_INSTALL_MKDIR }, { "gfig", USER_INSTALL_MKDIR }, { "gflare", USER_INSTALL_MKDIR }, { "gimpressionist", USER_INSTALL_MKDIR } }; static void user_install_log (GimpUserInstall *install, const gchar *format, ...) G_GNUC_PRINTF (2, 3); static void user_install_log_error (GimpUserInstall *install, GError **error); static gboolean user_install_mkdir (GimpUserInstall *install, const gchar *dirname); static gboolean user_install_file_copy (GimpUserInstall *install, const gchar *source, const gchar *dest); static gboolean user_install_dir_copy (GimpUserInstall *install, const gchar *source, const gchar *base); static gboolean user_install_create_files (GimpUserInstall *install); static gboolean user_install_migrate_files (GimpUserInstall *install); GimpUserInstall * gimp_user_install_new (gboolean verbose) { GimpUserInstall *install = g_new0 (GimpUserInstall, 1); gchar *dir; gchar *version; gboolean migrate; install->verbose = verbose; dir = g_strdup (gimp_directory ()); version = strstr (dir, GIMP_APP_VERSION); if (! version) { g_free (dir); return install; } /* we assume that GIMP_APP_VERSION is in the form '2.x' */ version[2] = '2'; migrate = g_file_test (dir, G_FILE_TEST_IS_DIR); if (migrate) { install->old_major = 2; install->old_minor = 2; } else { version[2] = '0'; migrate = g_file_test (dir, G_FILE_TEST_IS_DIR); if (migrate) { install->old_major = 2; install->old_minor = 0; } } if (migrate) { install->old_dir = dir; install->migrate = (const gchar *) version; } else { g_free (dir); } return install; } gboolean gimp_user_install_run (GimpUserInstall *install, gboolean migrate) { g_return_val_if_fail (install != NULL, FALSE); if (! user_install_mkdir (install, gimp_directory ())) return FALSE; if (migrate && install->migrate) return user_install_migrate_files (install); else return user_install_create_files (install); } void gimp_user_install_free (GimpUserInstall *install) { g_return_if_fail (install != NULL); g_free (install->old_dir); g_free (install); } gboolean gimp_user_install_is_migration (GimpUserInstall *install, gchar **version) { g_return_val_if_fail (install != NULL, FALSE); if (install->migrate) { if (version) *version = g_strdup (install->migrate); return TRUE; } return FALSE; } void gimp_user_install_set_log_handler (GimpUserInstall *install, GimpUserInstallLogFunc log, gpointer user_data) { g_return_if_fail (install != NULL); install->log = log; install->log_data = user_data; } /* Local functions */ static void user_install_log (GimpUserInstall *install, const gchar *format, ...) { va_list args; va_start (args, format); if (format) { gchar *message = g_strdup_vprintf (format, args); if (install->verbose) g_print ("%s\n", message); if (install->log) install->log (message, FALSE, install->log_data); g_free (message); } va_end (args); } static void user_install_log_error (GimpUserInstall *install, GError **error) { if (error && *error) { const gchar *message = ((*error)->message ? (*error)->message : "(unknown error)"); if (install->log) install->log (message, TRUE, install->log_data); else g_print ("error: %s\n", message); g_clear_error (error); } } static gboolean user_install_file_copy (GimpUserInstall *install, const gchar *source, const gchar *dest) { GError *error = NULL; gboolean success; user_install_log (install, _("Copying file '%s' from '%s'..."), gimp_filename_to_utf8 (dest), gimp_filename_to_utf8 (source)); success = gimp_config_file_copy (source, dest, &error); user_install_log_error (install, &error); return success; } static gboolean user_install_mkdir (GimpUserInstall *install, const gchar *dirname) { user_install_log (install, _("Creating folder '%s'..."), gimp_filename_to_utf8 (dirname)); if (g_mkdir (dirname, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) { GError *error = NULL; g_set_error (&error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Cannot create folder '%s': %s"), gimp_filename_to_utf8 (dirname), g_strerror (errno)); user_install_log_error (install, &error); return FALSE; } return TRUE; } static gboolean user_install_dir_copy (GimpUserInstall *install, const gchar *source, const gchar *base) { GDir *source_dir = NULL; GDir *dest_dir = NULL; gchar dest[1024]; const gchar *basename; gchar *dirname; gboolean success; GError *error = NULL; { gchar *basename = g_path_get_basename (source); dirname = g_build_filename (base, basename, NULL); g_free (basename); } success = user_install_mkdir (install, dirname); if (! success) goto error; success = (dest_dir = g_dir_open (dirname, 0, &error)) != NULL; if (! success) goto error; success = (source_dir = g_dir_open (source, 0, &error)) != NULL; if (! success) goto error; while ((basename = g_dir_read_name (source_dir)) != NULL) { gchar *name = g_build_filename (source, basename, NULL); if (g_file_test (name, G_FILE_TEST_IS_REGULAR)) { g_snprintf (dest, sizeof (dest), "%s%c%s", dirname, G_DIR_SEPARATOR, basename); if (! user_install_file_copy (install, name, dest)) { g_free (name); goto error; } } g_free (name); } error: user_install_log_error (install, &error); if (source_dir) g_dir_close (source_dir); if (dest_dir) g_dir_close (dest_dir); g_free (dirname); return success; } static gboolean user_install_create_files (GimpUserInstall *install) { gchar dest[1024]; gchar source[1024]; gint i; for (i = 0; i < G_N_ELEMENTS (gimp_user_install_items); i++) { g_snprintf (dest, sizeof (dest), "%s%c%s", gimp_directory (), G_DIR_SEPARATOR, gimp_user_install_items[i].name); switch (gimp_user_install_items[i].action) { case USER_INSTALL_MKDIR: if (! user_install_mkdir (install, dest)) return FALSE; break; case USER_INSTALL_COPY: g_snprintf (source, sizeof (source), "%s%c%s", gimp_sysconf_directory (), G_DIR_SEPARATOR, gimp_user_install_items[i].name); if (! user_install_file_copy (install, source, dest)) return FALSE; break; } } return TRUE; } static gboolean user_install_migrate_files (GimpUserInstall *install) { GDir *dir; const gchar *basename; gchar dest[1024]; GError *error = NULL; dir = g_dir_open (install->old_dir, 0, &error); if (! dir) { user_install_log_error (install, &error); return FALSE; } while ((basename = g_dir_read_name (dir)) != NULL) { gchar *source = g_build_filename (install->old_dir, basename, NULL); if (g_file_test (source, G_FILE_TEST_IS_REGULAR)) { /* skip these for all old versions */ if ((strncmp (basename, "gimpswap.", 9) == 0) || (strncmp (basename, "pluginrc", 8) == 0) || (strncmp (basename, "themerc", 7) == 0)) { goto next_file; } /* skip menurc for gimp 2.0 since the format has changed */ if (install->old_minor == 0 && (strncmp (basename, "menurc", 6) == 0)) { goto next_file; } g_snprintf (dest, sizeof (dest), "%s%c%s", gimp_directory (), G_DIR_SEPARATOR, basename); user_install_file_copy (install, source, dest); } else if (g_file_test (source, G_FILE_TEST_IS_DIR) && strcmp (basename, "tmp") != 0) { user_install_dir_copy (install, source, gimp_directory ()); } next_file: g_free (source); } /* create the tmp directory that was explicitely not copied */ g_snprintf (dest, sizeof (dest), "%s%c%s", gimp_directory (), G_DIR_SEPARATOR, "tmp"); user_install_mkdir (install, dest); g_dir_close (dir); gimp_templates_migrate (install->old_dir); return TRUE; }