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-2019
   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_SYNTAX_FILE},
  72     { "cedit" PATH_SEP_STR "menu",             &mc_config_str, EDIT_HOME_MENU},
  73     { "cedit" PATH_SEP_STR "edit.indent.rc",   &mc_config_str, EDIT_DIR PATH_SEP_STR "edit.indent.rc"},
  74     { "cedit" PATH_SEP_STR "edit.spell.rc",    &mc_config_str, EDIT_DIR PATH_SEP_STR "edit.spell.rc"},
  75     { "panels.ini",                            &mc_config_str, MC_PANELS_FILE},
  76 
  77     /* User should move this file with applying some changes in file */
  78     { "",                                      &mc_config_str, MC_FILEBIND_FILE},
  79 
  80     /* data */
  81     { "skins",                                 &mc_data_str, MC_SKINS_SUBDIR},
  82     { "fish",                                  &mc_data_str, FISH_PREFIX},
  83     { "ashrc",                                 &mc_data_str, "ashrc"},
  84     { "bashrc",                                &mc_data_str, "bashrc"},
  85     { "inputrc",                               &mc_data_str, "inputrc"},
  86     { "extfs.d",                               &mc_data_str, MC_EXTFS_DIR},
  87     { "history",                               &mc_data_str, MC_HISTORY_FILE},
  88     { "filepos",                               &mc_data_str, MC_FILEPOS_FILE},
  89     { "cedit" PATH_SEP_STR "cooledit.clip",    &mc_data_str, EDIT_CLIP_FILE},
  90     { "",                                      &mc_data_str, MC_MACRO_FILE},
  91 
  92     /* cache */
  93     { "log",                                   &mc_cache_str, "mc.log"},
  94     { "Tree",                                  &mc_cache_str, MC_TREESTORE_FILE},
  95     { "cedit" PATH_SEP_STR "cooledit.temp",    &mc_cache_str, EDIT_TEMP_FILE},
  96     { "cedit" PATH_SEP_STR "cooledit.block",   &mc_cache_str, EDIT_BLOCK_FILE},
  97 
  98     {NULL, NULL, NULL}
  99     /* *INDENT-ON* */
 100 };
 101 
 102 #if MC_HOMEDIR_XDG
 103 static const struct
 104 {
 105     char **old_basedir;
 106     const char *filename;
 107 
 108     char **new_basedir;
 109 } mc_config_migrate_rules_fix[] =
 110 {
 111     /* *INDENT-OFF* */
 112     { &mc_data_str, MC_USERMENU_FILE,                       &mc_config_str},
 113     { &mc_data_str, EDIT_SYNTAX_FILE,                       &mc_config_str},
 114     { &mc_data_str, EDIT_HOME_MENU,                         &mc_config_str},
 115     { &mc_data_str, EDIT_DIR PATH_SEP_STR "edit.indent.rc", &mc_config_str},
 116     { &mc_data_str, EDIT_DIR PATH_SEP_STR "edit.spell.rc",  &mc_config_str},
 117     { &mc_data_str, MC_FILEBIND_FILE,                       &mc_config_str},
 118 
 119     { &mc_cache_str, MC_HISTORY_FILE,                       &mc_data_str},
 120     { &mc_cache_str, MC_FILEPOS_FILE,                       &mc_data_str},
 121     { &mc_cache_str, EDIT_CLIP_FILE,                        &mc_data_str},
 122 
 123     { &mc_cache_str, MC_PANELS_FILE,                        &mc_config_str},
 124 
 125     {NULL, NULL, NULL}
 126     /* *INDENT-ON* */
 127 };
 128 #endif /* MC_HOMEDIR_XDG */
 129 
 130 /* --------------------------------------------------------------------------------------------- */
 131 /*** file scope functions *********************************************************************** */
 132 /* --------------------------------------------------------------------------------------------- */
 133 
 134 static void
 135 mc_config_mkdir (const char *directory_name, GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 136 {
 137     mc_return_if_error (mcerror);
 138 
 139     if ((!g_file_test (directory_name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) &&
 140         (g_mkdir_with_parents (directory_name, 0700) != 0))
 141         mc_propagate_error (mcerror, 0, _("Cannot create %s directory"), directory_name);
 142 }
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 
 146 static char *
 147 mc_config_init_one_config_path (const char *path_base, const char *subdir, GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 148 {
 149     char *full_path;
 150 
 151     mc_return_val_if_error (mcerror, FALSE);
 152 
 153     full_path = g_build_filename (path_base, subdir, (char *) NULL);
 154 
 155     if (g_file_test (full_path, G_FILE_TEST_EXISTS))
 156     {
 157         if (g_file_test (full_path, G_FILE_TEST_IS_DIR))
 158             config_dir_present = TRUE;
 159         else
 160         {
 161             fprintf (stderr, "%s %s\n", _("FATAL: not a directory:"), full_path);
 162             exit (EXIT_FAILURE);
 163         }
 164     }
 165 
 166     mc_config_mkdir (full_path, mcerror);
 167     if (mcerror != NULL && *mcerror != NULL)
 168         MC_PTR_FREE (full_path);
 169 
 170     return full_path;
 171 }
 172 
 173 /* --------------------------------------------------------------------------------------------- */
 174 
 175 static char *
 176 mc_config_get_deprecated_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 177 {
 178     return g_build_filename (mc_config_get_home_dir (), MC_OLD_USERCONF_DIR, (char *) NULL);
 179 }
 180 
 181 /* --------------------------------------------------------------------------------------------- */
 182 
 183 static void
 184 mc_config_copy (const char *old_name, const char *new_name, GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 185 {
 186     mc_return_if_error (mcerror);
 187 
 188     if (g_file_test (old_name, G_FILE_TEST_IS_REGULAR))
 189     {
 190         char *contents = NULL;
 191         size_t length;
 192 
 193         if (g_file_get_contents (old_name, &contents, &length, mcerror))
 194             g_file_set_contents (new_name, contents, length, mcerror);
 195 
 196         g_free (contents);
 197         return;
 198     }
 199 
 200     if (g_file_test (old_name, G_FILE_TEST_IS_DIR))
 201     {
 202         GDir *dir;
 203         const char *dir_name;
 204 
 205         dir = g_dir_open (old_name, 0, mcerror);
 206         if (dir == NULL)
 207             return;
 208 
 209         if (g_mkdir_with_parents (new_name, 0700) == -1)
 210         {
 211             g_dir_close (dir);
 212             mc_propagate_error (mcerror, 0,
 213                                 _("An error occurred while migrating user settings: %s"),
 214                                 unix_error_string (errno));
 215             return;
 216         }
 217 
 218         while ((dir_name = g_dir_read_name (dir)) != NULL)
 219         {
 220             char *old_name2, *new_name2;
 221 
 222             old_name2 = g_build_filename (old_name, dir_name, (char *) NULL);
 223             new_name2 = g_build_filename (new_name, dir_name, (char *) NULL);
 224             mc_config_copy (old_name2, new_name2, mcerror);
 225             g_free (new_name2);
 226             g_free (old_name2);
 227         }
 228     }
 229 }
 230 
 231 /* --------------------------------------------------------------------------------------------- */
 232 
 233 #if MC_HOMEDIR_XDG
 234 static void
 235 mc_config_fix_migrated_rules (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 236 {
 237     size_t rule_index;
 238 
 239     for (rule_index = 0; mc_config_migrate_rules_fix[rule_index].old_basedir != NULL; rule_index++)
 240     {
 241         char *old_name;
 242 
 243         old_name =
 244             g_build_filename (*mc_config_migrate_rules_fix[rule_index].old_basedir,
 245                               mc_config_migrate_rules_fix[rule_index].filename, (char *) NULL);
 246 
 247         if (g_file_test (old_name, G_FILE_TEST_EXISTS))
 248         {
 249             char *new_name;
 250             const char *basedir = *mc_config_migrate_rules_fix[rule_index].new_basedir;
 251             const char *filename = mc_config_migrate_rules_fix[rule_index].filename;
 252 
 253             new_name = g_build_filename (basedir, filename, (char *) NULL);
 254             rename (old_name, new_name);
 255             g_free (new_name);
 256         }
 257 
 258         g_free (old_name);
 259     }
 260 }
 261 #endif /* MC_HOMEDIR_XDG */
 262 
 263 /* --------------------------------------------------------------------------------------------- */
 264 
 265 static gboolean
 266 mc_config_deprecated_dir_present (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 267 {
 268     char *old_dir;
 269     gboolean is_present;
 270 
 271     old_dir = mc_config_get_deprecated_path ();
 272     is_present = g_file_test (old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
 273     g_free (old_dir);
 274 
 275     return is_present && !config_dir_present;
 276 }
 277 
 278 /* --------------------------------------------------------------------------------------------- */
 279 /*** public functions ****************************************************************************/
 280 /* --------------------------------------------------------------------------------------------- */
 281 
 282 void
 283 mc_config_init_config_paths (GError ** mcerror)
     /* [previous][next][first][last][top][bottom][index][help]  */
 284 {
 285     const char *profile_root;
 286     char *dir;
 287 #if MC_HOMEDIR_XDG == 0
 288     char *defined_userconf_dir;
 289 #endif
 290 
 291     mc_return_if_error (mcerror);
 292 
 293     if (xdg_vars_initialized)
 294         return;
 295 
 296     profile_root = mc_get_profile_root ();
 297 
 298 #if MC_HOMEDIR_XDG
 299     if (strcmp (profile_root, mc_config_get_home_dir ()) != 0)
 300     {
 301         /*
 302          * The user overrode the default profile root.
 303          *
 304          * In this case we can't use GLib's g_get_user_{config,cache,data}_dir()
 305          * as these functions use the user's home dir as the root.
 306          */
 307 
 308         dir = g_build_filename (profile_root, ".config", (char *) NULL);
 309         mc_config_str = mc_config_init_one_config_path (dir, MC_USERCONF_DIR, mcerror);
 310         g_free (dir);
 311 
 312         dir = g_build_filename (profile_root, ".cache", (char *) NULL);
 313         mc_cache_str = mc_config_init_one_config_path (dir, MC_USERCONF_DIR, mcerror);
 314         g_free (dir);
 315 
 316         dir = g_build_filename (profile_root, ".local", "share", (char *) NULL);
 317         mc_data_str = mc_config_init_one_config_path (dir, MC_USERCONF_DIR, mcerror);
 318         g_free (dir);
 319     }
 320     else
 321     {
 322         mc_config_str =
 323             mc_config_init_one_config_path (g_get_user_config_dir (), MC_USERCONF_DIR, mcerror);
 324         mc_cache_str =
 325             mc_config_init_one_config_path (g_get_user_cache_dir (), MC_USERCONF_DIR, mcerror);
 326         mc_data_str =
 327             mc_config_init_one_config_path (g_get_user_data_dir (), MC_USERCONF_DIR, mcerror);
 328     }
 329 
 330     mc_config_fix_migrated_rules ();
 331 #else /* MC_HOMEDIR_XDG */
 332     defined_userconf_dir = tilde_expand (MC_USERCONF_DIR);
 333     if (g_path_is_absolute (defined_userconf_dir))
 334         dir = defined_userconf_dir;
 335     else
 336     {
 337         g_free (defined_userconf_dir);
 338         dir = g_build_filename (profile_root, MC_USERCONF_DIR, (char *) NULL);
 339     }
 340 
 341     mc_data_str = mc_cache_str = mc_config_str = mc_config_init_one_config_path (dir, "", mcerror);
 342 
 343     g_free (dir);
 344 #endif /* MC_HOMEDIR_XDG */
 345 
 346     xdg_vars_initialized = TRUE;
 347 }
 348 
 349 /* --------------------------------------------------------------------------------------------- */
 350 
 351 void
 352 mc_config_deinit_config_paths (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 353 {
 354     if (!xdg_vars_initialized)
 355         return;
 356 
 357     g_free (mc_config_str);
 358 #if MC_HOMEDIR_XDG
 359     g_free (mc_cache_str);
 360     g_free (mc_data_str);
 361 #endif /* MC_HOMEDIR_XDG */
 362 
 363     g_free (mc_global.share_data_dir);
 364     g_free (mc_global.sysconfig_dir);
 365 
 366     xdg_vars_initialized = FALSE;
 367 }
 368 
 369 /* --------------------------------------------------------------------------------------------- */
 370 
 371 const char *
 372 mc_config_get_data_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 373 {
 374     if (!xdg_vars_initialized)
 375         mc_config_init_config_paths (NULL);
 376 
 377     return (const char *) mc_data_str;
 378 }
 379 
 380 /* --------------------------------------------------------------------------------------------- */
 381 
 382 const char *
 383 mc_config_get_cache_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 384 {
 385     if (!xdg_vars_initialized)
 386         mc_config_init_config_paths (NULL);
 387 
 388     return (const char *) mc_cache_str;
 389 }
 390 
 391 /* --------------------------------------------------------------------------------------------- */
 392 
 393 const char *
 394 mc_config_get_home_dir (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 395 {
 396     static const char *homedir = NULL;
 397 
 398     if (homedir == NULL)
 399     {
 400         /* Prior to GLib 2.36, g_get_home_dir() ignores $HOME, which is why
 401          * we read it ourselves. As that function's documentation explains,
 402          * using $HOME is good for compatibility with other programs and
 403          * for running from test frameworks. */
 404         homedir = g_getenv ("HOME");
 405         if (homedir == NULL || *homedir == '\0')
 406             homedir = g_get_home_dir ();
 407     }
 408 
 409     return homedir;
 410 }
 411 
 412 /* --------------------------------------------------------------------------------------------- */
 413 
 414 const char *
 415 mc_config_get_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 416 {
 417     if (!xdg_vars_initialized)
 418         mc_config_init_config_paths (NULL);
 419 
 420     return (const char *) mc_config_str;
 421 }
 422 
 423 /* --------------------------------------------------------------------------------------------- */
 424 
 425 gboolean
 426 mc_config_migrate_from_old_place (GError ** mcerror, char **msg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 427 {
 428     char *old_dir;
 429     size_t rule_index;
 430 
 431     mc_return_val_if_error (mcerror, FALSE);
 432 
 433     if (!mc_config_deprecated_dir_present ())
 434         return FALSE;
 435 
 436     old_dir = mc_config_get_deprecated_path ();
 437 
 438     g_free (mc_config_init_one_config_path (mc_config_str, EDIT_DIR, mcerror));
 439 #if MC_HOMEDIR_XDG
 440     g_free (mc_config_init_one_config_path (mc_cache_str, EDIT_DIR, mcerror));
 441     g_free (mc_config_init_one_config_path (mc_data_str, EDIT_DIR, mcerror));
 442 #endif /* MC_HOMEDIR_XDG */
 443 
 444     mc_return_val_if_error (mcerror, FALSE);
 445 
 446     for (rule_index = 0; mc_config_files_reference[rule_index].old_filename != NULL; rule_index++)
 447     {
 448         char *old_name;
 449 
 450         if (*mc_config_files_reference[rule_index].old_filename == '\0')
 451             continue;
 452 
 453         old_name =
 454             g_build_filename (old_dir, mc_config_files_reference[rule_index].old_filename,
 455                               (char *) NULL);
 456 
 457         if (g_file_test (old_name, G_FILE_TEST_EXISTS))
 458         {
 459             char *new_name;
 460             const char *basedir = *mc_config_files_reference[rule_index].new_basedir;
 461             const char *filename = mc_config_files_reference[rule_index].new_filename;
 462 
 463             new_name = g_build_filename (basedir, filename, (char *) NULL);
 464             mc_config_copy (old_name, new_name, mcerror);
 465             g_free (new_name);
 466         }
 467 
 468         g_free (old_name);
 469     }
 470 
 471 #if MC_HOMEDIR_XDG
 472     *msg = g_strdup_printf (_("Your old settings were migrated from %s\n"
 473                               "to Freedesktop recommended dirs.\n"
 474                               "To get more info, please visit\n"
 475                               "http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html"),
 476                             old_dir);
 477 #else /* MC_HOMEDIR_XDG */
 478     *msg = g_strdup_printf (_("Your old settings were migrated from %s\n"
 479                               "to %s\n"), old_dir, mc_config_str);
 480 #endif /* MC_HOMEDIR_XDG */
 481 
 482     g_free (old_dir);
 483 
 484     return TRUE;
 485 }
 486 
 487 /* --------------------------------------------------------------------------------------------- */
 488 /**
 489  * Get full path to config file by short name.
 490  *
 491  * @param config_name short name
 492  * @return full path to config file
 493  */
 494 
 495 char *
 496 mc_config_get_full_path (const char *config_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 497 {
 498     size_t rule_index;
 499 
 500     if (config_name == NULL)
 501         return NULL;
 502 
 503     if (!xdg_vars_initialized)
 504         mc_config_init_config_paths (NULL);
 505 
 506     for (rule_index = 0; mc_config_files_reference[rule_index].old_filename != NULL; rule_index++)
 507         if (strcmp (config_name, mc_config_files_reference[rule_index].new_filename) == 0)
 508             return g_build_filename (*mc_config_files_reference[rule_index].new_basedir,
 509                                      mc_config_files_reference[rule_index].new_filename,
 510                                      (char *) NULL);
 511 
 512     return NULL;
 513 }
 514 
 515 /* --------------------------------------------------------------------------------------------- */
 516 /**
 517  * Get full path to config file by short name.
 518  *
 519  * @param config_name short name
 520  * @return object with full path to config file
 521  */
 522 
 523 vfs_path_t *
 524 mc_config_get_full_vpath (const char *config_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 525 {
 526     vfs_path_t *ret_vpath;
 527     char *str_path;
 528 
 529     str_path = mc_config_get_full_path (config_name);
 530 
 531     ret_vpath = vfs_path_from_str (str_path);
 532     g_free (str_path);
 533 
 534     return ret_vpath;
 535 }
 536 
 537 /* --------------------------------------------------------------------------------------------- */

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