root/lib/mcconfig/paths.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. mc_config_mkdir
  2. mc_config_init_one_config_path
  3. mc_config_get_deprecated_path
  4. mc_config_copy
  5. mc_config_fix_migrated_rules
  6. mc_config_deprecated_dir_present
  7. mc_config_init_config_paths
  8. mc_config_deinit_config_paths
  9. mc_config_get_data_path
  10. mc_config_get_cache_path
  11. mc_config_get_home_dir
  12. mc_config_get_path
  13. mc_config_migrate_from_old_place
  14. mc_config_get_full_path
  15. mc_config_get_full_vpath

   1 /*
   2    paths to configuration files
   3 
   4    Copyright (C) 2010-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2010.
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 #include <config.h>
  27 
  28 #include <stdio.h>
  29 #include <stdlib.h>
  30 #include <errno.h>
  31 
  32 #include "lib/global.h"
  33 #include "lib/fileloc.h"
  34 #include "lib/vfs/vfs.h"
  35 #include "lib/util.h"           /* unix_error_string() */
  36 
  37 #include "lib/mcconfig.h"
  38 
  39 /*** global variables ****************************************************************************/
  40 
  41 /*** file scope macro definitions ****************************************************************/
  42 
  43 #define MC_OLD_USERCONF_DIR ".mc"
  44 
  45 /*** file scope type declarations ****************************************************************/
  46 
  47 /*** file scope variables ************************************************************************/
  48 
  49 static gboolean xdg_vars_initialized = FALSE;
  50 static char *mc_config_str = NULL;
  51 static char *mc_cache_str = NULL;
  52 static char *mc_data_str = NULL;
  53 
  54 static gboolean config_dir_present = FALSE;
  55 
  56 static const struct
  57 {
  58     const char *old_filename;
  59 
  60     char **new_basedir;
  61     const char *new_filename;
  62 } mc_config_files_reference[] =
  63 {
  64     /* *INDENT-OFF* */
  65     /* config */
  66     { "ini",                                 &mc_config_str, MC_CONFIG_FILE },
  67     { "filehighlight.ini",                   &mc_config_str, MC_FHL_INI_FILE },
  68     { "hotlist",                             &mc_config_str, MC_HOTLIST_FILE },
  69     { "mc.keymap",                           &mc_config_str, GLOBAL_KEYMAP_FILE },
  70     { "menu",                                &mc_config_str, MC_USERMENU_FILE },
  71     { "cedit" PATH_SEP_STR "Syntax",         &mc_config_str, EDIT_HOME_SYNTAX_FILE },
  72     { "cedit" PATH_SEP_STR "menu",           &mc_config_str, EDIT_HOME_MENU },
  73     { "panels.ini",                          &mc_config_str, MC_PANELS_FILE },
  74 
  75     /* User should move this file with applying some changes in file */
  76     { "",                                    &mc_config_str, MC_FILEBIND_FILE },
  77 
  78     /* data */
  79     { "skins",                               &mc_data_str, MC_SKINS_DIR },
  80     { "fish",                                &mc_data_str, FISH_PREFIX },
  81     { "ashrc",                               &mc_data_str, "ashrc" },
  82     { "bashrc",                              &mc_data_str, "bashrc" },
  83     { "inputrc",                             &mc_data_str, "inputrc" },
  84     { "extfs.d",                             &mc_data_str, MC_EXTFS_DIR },
  85     { "history",                             &mc_data_str, MC_HISTORY_FILE },
  86     { "filepos",                             &mc_data_str, MC_FILEPOS_FILE },
  87     { "cedit" PATH_SEP_STR "cooledit.clip",  &mc_data_str, EDIT_HOME_CLIP_FILE },
  88     { "",                                    &mc_data_str, MC_MACRO_FILE },
  89 
  90     /* cache */
  91     { "log",                                 &mc_cache_str, "mc.log" },
  92     { "Tree",                                &mc_cache_str, MC_TREESTORE_FILE },
  93     { "cedit" PATH_SEP_STR "cooledit.temp",  &mc_cache_str, EDIT_HOME_TEMP_FILE },
  94     { "cedit" PATH_SEP_STR "cooledit.block", &mc_cache_str, EDIT_HOME_BLOCK_FILE },
  95 
  96     {NULL, NULL, NULL}
  97     /* *INDENT-ON* */
  98 };
  99 
 100 #if MC_HOMEDIR_XDG
 101 static const struct
 102 {
 103     char **old_basedir;
 104     const char *filename;
 105 
 106     char **new_basedir;
 107 } mc_config_migrate_rules_fix[] =
 108 {
 109     /* *INDENT-OFF* */
 110     { &mc_data_str, MC_USERMENU_FILE,      &mc_config_str },
 111     { &mc_data_str, MC_FILEBIND_FILE,      &mc_config_str },
 112     { &mc_data_str, EDIT_HOME_SYNTAX_FILE, &mc_config_str },
 113     { &mc_data_str, EDIT_HOME_MENU,        &mc_config_str },
 114 
 115     { &mc_cache_str, MC_PANELS_FILE,       &mc_config_str },
 116     { &mc_cache_str, MC_HISTORY_FILE,      &mc_data_str },
 117     { &mc_cache_str, MC_FILEPOS_FILE,      &mc_data_str },
 118     { &mc_cache_str, EDIT_HOME_CLIP_FILE,  &mc_data_str },
 119 
 120     { NULL, NULL, NULL }
 121     /* *INDENT-ON* */
 122 };
 123 #endif /* MC_HOMEDIR_XDG */
 124 
 125 /* --------------------------------------------------------------------------------------------- */
 126 /*** file scope functions *********************************************************************** */
 127 /* --------------------------------------------------------------------------------------------- */
 128 
 129 static void
 130 mc_config_mkdir (const char *directory_name, GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 131 {
 132     mc_return_if_error (mcerror);
 133 
 134     if ((!g_file_test (directory_name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) &&
 135         (g_mkdir_with_parents (directory_name, 0700) != 0))
 136         mc_propagate_error (mcerror, 0, _("Cannot create %s directory"), directory_name);
 137 }
 138 
 139 /* --------------------------------------------------------------------------------------------- */
 140 
 141 static char *
 142 mc_config_init_one_config_path (const char *path_base, const char *subdir, GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 143 {
 144     char *full_path;
 145 
 146     mc_return_val_if_error (mcerror, FALSE);
 147 
 148     full_path = g_build_filename (path_base, subdir, (char *) NULL);
 149 
 150     if (g_file_test (full_path, G_FILE_TEST_EXISTS))
 151     {
 152         if (g_file_test (full_path, G_FILE_TEST_IS_DIR))
 153             config_dir_present = TRUE;
 154         else
 155         {
 156             fprintf (stderr, "%s %s\n", _("FATAL: not a directory:"), full_path);
 157             exit (EXIT_FAILURE);
 158         }
 159     }
 160 
 161     mc_config_mkdir (full_path, mcerror);
 162     if (mcerror != NULL && *mcerror != NULL)
 163         MC_PTR_FREE (full_path);
 164 
 165     return full_path;
 166 }
 167 
 168 /* --------------------------------------------------------------------------------------------- */
 169 
 170 static char *
 171 mc_config_get_deprecated_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 172 {
 173     return g_build_filename (mc_config_get_home_dir (), MC_OLD_USERCONF_DIR, (char *) NULL);
 174 }
 175 
 176 /* --------------------------------------------------------------------------------------------- */
 177 
 178 static void
 179 mc_config_copy (const char *old_name, const char *new_name, GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 180 {
 181     mc_return_if_error (mcerror);
 182 
 183     if (g_file_test (old_name, G_FILE_TEST_IS_REGULAR))
 184     {
 185         char *contents = NULL;
 186         size_t length;
 187 
 188         if (g_file_get_contents (old_name, &contents, &length, mcerror))
 189             g_file_set_contents (new_name, contents, length, mcerror);
 190 
 191         g_free (contents);
 192         return;
 193     }
 194 
 195     if (g_file_test (old_name, G_FILE_TEST_IS_DIR))
 196     {
 197         GDir *dir;
 198         const char *dir_name;
 199 
 200         dir = g_dir_open (old_name, 0, mcerror);
 201         if (dir == NULL)
 202             return;
 203 
 204         if (g_mkdir_with_parents (new_name, 0700) == -1)
 205         {
 206             g_dir_close (dir);
 207             mc_propagate_error (mcerror, 0,
 208                                 _("An error occurred while migrating user settings: %s"),
 209                                 unix_error_string (errno));
 210             return;
 211         }
 212 
 213         while ((dir_name = g_dir_read_name (dir)) != NULL)
 214         {
 215             char *old_name2, *new_name2;
 216 
 217             old_name2 = g_build_filename (old_name, dir_name, (char *) NULL);
 218             new_name2 = g_build_filename (new_name, dir_name, (char *) NULL);
 219             mc_config_copy (old_name2, new_name2, mcerror);
 220             g_free (new_name2);
 221             g_free (old_name2);
 222         }
 223     }
 224 }
 225 
 226 /* --------------------------------------------------------------------------------------------- */
 227 
 228 #if MC_HOMEDIR_XDG
 229 static void
 230 mc_config_fix_migrated_rules (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 231 {
 232     size_t rule_index;
 233 
 234     for (rule_index = 0; mc_config_migrate_rules_fix[rule_index].old_basedir != NULL; rule_index++)
 235     {
 236         char *old_name;
 237 
 238         old_name =
 239             g_build_filename (*mc_config_migrate_rules_fix[rule_index].old_basedir,
 240                               mc_config_migrate_rules_fix[rule_index].filename, (char *) NULL);
 241 
 242         if (g_file_test (old_name, G_FILE_TEST_EXISTS))
 243         {
 244             char *new_name;
 245             const char *basedir = *mc_config_migrate_rules_fix[rule_index].new_basedir;
 246             const char *filename = mc_config_migrate_rules_fix[rule_index].filename;
 247 
 248             new_name = g_build_filename (basedir, filename, (char *) NULL);
 249             rename (old_name, new_name);
 250             g_free (new_name);
 251         }
 252 
 253         g_free (old_name);
 254     }
 255 }
 256 #endif /* MC_HOMEDIR_XDG */
 257 
 258 /* --------------------------------------------------------------------------------------------- */
 259 
 260 static gboolean
 261 mc_config_deprecated_dir_present (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 262 {
 263     char *old_dir;
 264     gboolean is_present;
 265 
 266     old_dir = mc_config_get_deprecated_path ();
 267     is_present = g_file_test (old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
 268     g_free (old_dir);
 269 
 270     return is_present && !config_dir_present;
 271 }
 272 
 273 /* --------------------------------------------------------------------------------------------- */
 274 /*** public functions ****************************************************************************/
 275 /* --------------------------------------------------------------------------------------------- */
 276 
 277 void
 278 mc_config_init_config_paths (GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 279 {
 280     const char *profile_root;
 281     char *dir;
 282 #if MC_HOMEDIR_XDG == 0
 283     char *defined_userconf_dir;
 284 #endif
 285 
 286     mc_return_if_error (mcerror);
 287 
 288     if (xdg_vars_initialized)
 289         return;
 290 
 291     profile_root = mc_get_profile_root ();
 292 
 293 #if MC_HOMEDIR_XDG
 294     if (strcmp (profile_root, mc_config_get_home_dir ()) != 0)
 295     {
 296         /*
 297          * The user overrode the default profile root.
 298          *
 299          * In this case we can't use GLib's g_get_user_{config,cache,data}_dir()
 300          * as these functions use the user's home dir as the root.
 301          */
 302 
 303         dir = g_build_filename (profile_root, ".config", (char *) NULL);
 304         mc_config_str = mc_config_init_one_config_path (dir, MC_USERCONF_DIR, mcerror);
 305         g_free (dir);
 306 
 307         dir = g_build_filename (profile_root, ".cache", (char *) NULL);
 308         mc_cache_str = mc_config_init_one_config_path (dir, MC_USERCONF_DIR, mcerror);
 309         g_free (dir);
 310 
 311         dir = g_build_filename (profile_root, ".local", "share", (char *) NULL);
 312         mc_data_str = mc_config_init_one_config_path (dir, MC_USERCONF_DIR, mcerror);
 313         g_free (dir);
 314     }
 315     else
 316     {
 317         mc_config_str =
 318             mc_config_init_one_config_path (g_get_user_config_dir (), MC_USERCONF_DIR, mcerror);
 319         mc_cache_str =
 320             mc_config_init_one_config_path (g_get_user_cache_dir (), MC_USERCONF_DIR, mcerror);
 321         mc_data_str =
 322             mc_config_init_one_config_path (g_get_user_data_dir (), MC_USERCONF_DIR, mcerror);
 323     }
 324 
 325     mc_config_fix_migrated_rules ();
 326 #else /* MC_HOMEDIR_XDG */
 327     defined_userconf_dir = tilde_expand (MC_USERCONF_DIR);
 328     if (g_path_is_absolute (defined_userconf_dir))
 329         dir = defined_userconf_dir;
 330     else
 331     {
 332         g_free (defined_userconf_dir);
 333         dir = g_build_filename (profile_root, MC_USERCONF_DIR, (char *) NULL);
 334     }
 335 
 336     mc_data_str = mc_cache_str = mc_config_str = mc_config_init_one_config_path (dir, "", mcerror);
 337 
 338     g_free (dir);
 339 #endif /* MC_HOMEDIR_XDG */
 340 
 341     xdg_vars_initialized = TRUE;
 342 }
 343 
 344 /* --------------------------------------------------------------------------------------------- */
 345 
 346 void
 347 mc_config_deinit_config_paths (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 348 {
 349     if (!xdg_vars_initialized)
 350         return;
 351 
 352     g_free (mc_config_str);
 353 #if MC_HOMEDIR_XDG
 354     g_free (mc_cache_str);
 355     g_free (mc_data_str);
 356 #endif /* MC_HOMEDIR_XDG */
 357 
 358     g_free (mc_global.share_data_dir);
 359     g_free (mc_global.sysconfig_dir);
 360 
 361     xdg_vars_initialized = FALSE;
 362 }
 363 
 364 /* --------------------------------------------------------------------------------------------- */
 365 
 366 const char *
 367 mc_config_get_data_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 368 {
 369     if (!xdg_vars_initialized)
 370         mc_config_init_config_paths (NULL);
 371 
 372     return (const char *) mc_data_str;
 373 }
 374 
 375 /* --------------------------------------------------------------------------------------------- */
 376 
 377 const char *
 378 mc_config_get_cache_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 379 {
 380     if (!xdg_vars_initialized)
 381         mc_config_init_config_paths (NULL);
 382 
 383     return (const char *) mc_cache_str;
 384 }
 385 
 386 /* --------------------------------------------------------------------------------------------- */
 387 
 388 const char *
 389 mc_config_get_home_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 390 {
 391     static const char *homedir = NULL;
 392 
 393     if (homedir == NULL)
 394     {
 395         /* Prior to GLib 2.36, g_get_home_dir() ignores $HOME, which is why
 396          * we read it ourselves. As that function's documentation explains,
 397          * using $HOME is good for compatibility with other programs and
 398          * for running from test frameworks. */
 399         homedir = g_getenv ("HOME");
 400         if (homedir == NULL || *homedir == '\0')
 401             homedir = g_get_home_dir ();
 402     }
 403 
 404     return homedir;
 405 }
 406 
 407 /* --------------------------------------------------------------------------------------------- */
 408 
 409 const char *
 410 mc_config_get_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 411 {
 412     if (!xdg_vars_initialized)
 413         mc_config_init_config_paths (NULL);
 414 
 415     return (const char *) mc_config_str;
 416 }
 417 
 418 /* --------------------------------------------------------------------------------------------- */
 419 
 420 gboolean
 421 mc_config_migrate_from_old_place (GError ** mcerror, char **msg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 422 {
 423     char *old_dir;
 424     size_t rule_index;
 425 
 426     mc_return_val_if_error (mcerror, FALSE);
 427 
 428     if (!mc_config_deprecated_dir_present ())
 429         return FALSE;
 430 
 431     old_dir = mc_config_get_deprecated_path ();
 432 
 433     g_free (mc_config_init_one_config_path (mc_config_str, EDIT_HOME_DIR, mcerror));
 434 #if MC_HOMEDIR_XDG
 435     g_free (mc_config_init_one_config_path (mc_cache_str, EDIT_HOME_DIR, mcerror));
 436     g_free (mc_config_init_one_config_path (mc_data_str, EDIT_HOME_DIR, mcerror));
 437 #endif /* MC_HOMEDIR_XDG */
 438 
 439     mc_return_val_if_error (mcerror, FALSE);
 440 
 441     for (rule_index = 0; mc_config_files_reference[rule_index].old_filename != NULL; rule_index++)
 442     {
 443         char *old_name;
 444 
 445         if (*mc_config_files_reference[rule_index].old_filename == '\0')
 446             continue;
 447 
 448         old_name =
 449             g_build_filename (old_dir, mc_config_files_reference[rule_index].old_filename,
 450                               (char *) NULL);
 451 
 452         if (g_file_test (old_name, G_FILE_TEST_EXISTS))
 453         {
 454             char *new_name;
 455             const char *basedir = *mc_config_files_reference[rule_index].new_basedir;
 456             const char *filename = mc_config_files_reference[rule_index].new_filename;
 457 
 458             new_name = g_build_filename (basedir, filename, (char *) NULL);
 459             mc_config_copy (old_name, new_name, mcerror);
 460             g_free (new_name);
 461         }
 462 
 463         g_free (old_name);
 464     }
 465 
 466 #if MC_HOMEDIR_XDG
 467     *msg = g_strdup_printf (_("Your old settings were migrated from %s\n"
 468                               "to Freedesktop recommended dirs.\n"
 469                               "To get more info, please visit\n"
 470                               "http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html"),
 471                             old_dir);
 472 #else /* MC_HOMEDIR_XDG */
 473     *msg = g_strdup_printf (_("Your old settings were migrated from %s\n"
 474                               "to %s\n"), old_dir, mc_config_str);
 475 #endif /* MC_HOMEDIR_XDG */
 476 
 477     g_free (old_dir);
 478 
 479     return TRUE;
 480 }
 481 
 482 /* --------------------------------------------------------------------------------------------- */
 483 /**
 484  * Get full path to config file by short name.
 485  *
 486  * @param config_name short name
 487  * @return full path to config file
 488  */
 489 
 490 char *
 491 mc_config_get_full_path (const char *config_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 492 {
 493     size_t rule_index;
 494 
 495     if (config_name == NULL)
 496         return NULL;
 497 
 498     if (!xdg_vars_initialized)
 499         mc_config_init_config_paths (NULL);
 500 
 501     for (rule_index = 0; mc_config_files_reference[rule_index].old_filename != NULL; rule_index++)
 502         if (strcmp (config_name, mc_config_files_reference[rule_index].new_filename) == 0)
 503             return g_build_filename (*mc_config_files_reference[rule_index].new_basedir,
 504                                      mc_config_files_reference[rule_index].new_filename,
 505                                      (char *) NULL);
 506 
 507     return NULL;
 508 }
 509 
 510 /* --------------------------------------------------------------------------------------------- */
 511 /**
 512  * Get full path to config file by short name.
 513  *
 514  * @param config_name short name
 515  * @return object with full path to config file
 516  */
 517 
 518 vfs_path_t *
 519 mc_config_get_full_vpath (const char *config_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 520 {
 521     vfs_path_t *ret_vpath;
 522     char *str_path;
 523 
 524     str_path = mc_config_get_full_path (config_name);
 525 
 526     ret_vpath = vfs_path_from_str (str_path);
 527     g_free (str_path);
 528 
 529     return ret_vpath;
 530 }
 531 
 532 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */