paths.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. paths to configuration files
  3. Copyright (C) 2010 The Free Software Foundation, Inc.
  4. Written by:
  5. Slava Zanko <slavazanko@gmail.com>, 2010.
  6. This file is part of the Midnight Commander.
  7. The Midnight Commander is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU General Public License as
  9. published by the Free Software Foundation; either version 2 of the
  10. License, or (at your option) any later version.
  11. The Midnight Commander is distributed in the hope that it will be
  12. useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  13. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  18. MA 02110-1301, USA.
  19. */
  20. #include <config.h>
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include "lib/global.h"
  24. #include "lib/fileloc.h"
  25. #include "lib/vfs/vfs.h"
  26. #include "lib/util.h" /* unix_error_string() */
  27. #include "lib/mcconfig.h"
  28. /*** global variables ****************************************************************************/
  29. /*** file scope macro definitions ****************************************************************/
  30. /*** file scope type declarations ****************************************************************/
  31. /*** file scope variables ************************************************************************/
  32. static gboolean xdg_vars_initialized = FALSE;
  33. static char *xdg_config = NULL;
  34. static char *xdg_cache = NULL;
  35. static char *xdg_data = NULL;
  36. static const char *homedir = NULL;
  37. static gboolean config_dir_present = FALSE;
  38. static const struct
  39. {
  40. const char *old_filename;
  41. char **new_basedir;
  42. const char *new_filename;
  43. } mc_config_migrate_rules[] =
  44. {
  45. /* *INDENT-OFF* */
  46. /* config */
  47. { "ini", &xdg_config, MC_CONFIG_FILE},
  48. { "filehighlight.ini", &xdg_config, MC_FHL_INI_FILE},
  49. { "hotlist", &xdg_config, MC_HOTLIST_FILE},
  50. { "mc.keymap", &xdg_config, GLOBAL_KEYMAP_FILE},
  51. /* data */
  52. { "skins", &xdg_data, MC_SKINS_SUBDIR},
  53. { "fish", &xdg_data, FISH_PREFIX},
  54. { "bindings", &xdg_data, MC_FILEBIND_FILE},
  55. { "menu", &xdg_data, MC_USERMENU_FILE},
  56. { "bashrc", &xdg_data, "bashrc"},
  57. { "inputrc", &xdg_data, "inputrc"},
  58. { "extfs.d", &xdg_data, MC_EXTFS_DIR},
  59. { "cedit" PATH_SEP_STR "Syntax", &xdg_data, EDIT_SYNTAX_FILE},
  60. { "cedit" PATH_SEP_STR "menu", &xdg_data, EDIT_HOME_MENU},
  61. { "cedit" PATH_SEP_STR "edit.indent.rc", &xdg_data, EDIT_DIR PATH_SEP_STR "edit.indent.rc"},
  62. { "cedit" PATH_SEP_STR "edit.spell.rc", &xdg_data, EDIT_DIR PATH_SEP_STR "edit.spell.rc"},
  63. /* cache */
  64. { "history", &xdg_cache, MC_HISTORY_FILE},
  65. { "panels.ini", &xdg_cache, MC_PANELS_FILE},
  66. { "log", &xdg_cache, "mc.log"},
  67. { "filepos", &xdg_cache, MC_FILEPOS_FILE},
  68. { "Tree", &xdg_cache, MC_TREESTORE_FILE},
  69. { "cedit" PATH_SEP_STR "cooledit.clip", &xdg_cache, EDIT_CLIP_FILE},
  70. { "cedit" PATH_SEP_STR "cooledit.temp", &xdg_cache, EDIT_TEMP_FILE},
  71. { "cedit" PATH_SEP_STR "cooledit.block", &xdg_cache, EDIT_BLOCK_FILE},
  72. {NULL, NULL, NULL}
  73. /* *INDENT-ON* */
  74. };
  75. /*** file scope functions *********************************************************************** */
  76. /* --------------------------------------------------------------------------------------------- */
  77. static void
  78. mc_config_mkdir (const char *directory_name, GError ** error)
  79. {
  80. if ((!g_file_test (directory_name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) &&
  81. (g_mkdir_with_parents (directory_name, 0700) != 0))
  82. {
  83. g_propagate_error (error,
  84. g_error_new (MC_ERROR, 0, _("Cannot create %s directory"),
  85. directory_name));
  86. }
  87. }
  88. /* --------------------------------------------------------------------------------------------- */
  89. static char *
  90. mc_config_init_one_config_path (const char *path_base, const char *subdir, GError ** error)
  91. {
  92. char *full_path;
  93. full_path = g_build_filename (path_base, subdir, NULL);
  94. if (g_file_test (full_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
  95. config_dir_present = TRUE;
  96. mc_config_mkdir (full_path, error);
  97. if (error != NULL && *error != NULL)
  98. {
  99. g_free (full_path);
  100. full_path = NULL;
  101. }
  102. return full_path;
  103. }
  104. /* --------------------------------------------------------------------------------------------- */
  105. static char *
  106. mc_config_get_deprecated_path (void)
  107. {
  108. return g_build_filename (mc_config_get_home_dir (), "." MC_USERCONF_DIR, NULL);
  109. }
  110. /* --------------------------------------------------------------------------------------------- */
  111. static void
  112. mc_config_copy (const char *old_name, const char *new_name, GError ** error)
  113. {
  114. if (g_file_test (old_name, G_FILE_TEST_IS_REGULAR))
  115. {
  116. char *contents = NULL;
  117. size_t length;
  118. if (g_file_get_contents (old_name, &contents, &length, error))
  119. g_file_set_contents (new_name, contents, length, error);
  120. g_free (contents);
  121. return;
  122. }
  123. if (g_file_test (old_name, G_FILE_TEST_IS_DIR))
  124. {
  125. GDir *dir;
  126. const char *dir_name;
  127. dir = g_dir_open (old_name, 0, error);
  128. if (dir == NULL)
  129. return;
  130. if (g_mkdir_with_parents (new_name, 0700) == -1)
  131. {
  132. g_dir_close (dir);
  133. g_propagate_error (error,
  134. g_error_new (MC_ERROR, 0,
  135. _
  136. ("An error occured while migrating user settings: %s"),
  137. unix_error_string (errno)));
  138. return;
  139. }
  140. while ((dir_name = g_dir_read_name (dir)) != NULL)
  141. {
  142. char *old_name2, *new_name2;
  143. old_name2 = g_build_filename (old_name, dir_name, NULL);
  144. new_name2 = g_build_filename (new_name, dir_name, NULL);
  145. mc_config_copy (old_name2, new_name2, error);
  146. g_free (new_name2);
  147. g_free (old_name2);
  148. }
  149. }
  150. }
  151. /* --------------------------------------------------------------------------------------------- */
  152. /*** public functions ****************************************************************************/
  153. /* --------------------------------------------------------------------------------------------- */
  154. void
  155. mc_config_init_config_paths (GError ** error)
  156. {
  157. const char *mc_datadir;
  158. char *u_config_dir = (char *) g_get_user_config_dir ();
  159. char *u_data_dir = (char *) g_get_user_data_dir ();
  160. char *u_cache_dir = (char *) g_get_user_cache_dir ();
  161. if (xdg_vars_initialized)
  162. return;
  163. u_config_dir = (u_config_dir == NULL)
  164. ? g_build_filename (mc_config_get_home_dir (), ".config", NULL) : g_strdup (u_config_dir);
  165. u_cache_dir = (u_cache_dir == NULL)
  166. ? g_build_filename (mc_config_get_home_dir (), ".cache", NULL) : g_strdup (u_cache_dir);
  167. u_data_dir = (u_data_dir == NULL)
  168. ? g_build_filename (mc_config_get_home_dir (), ".local", "share", NULL)
  169. : g_strdup (u_data_dir);
  170. xdg_config = mc_config_init_one_config_path (u_config_dir, MC_USERCONF_DIR, error);
  171. xdg_cache = mc_config_init_one_config_path (u_cache_dir, MC_USERCONF_DIR, error);
  172. xdg_data = mc_config_init_one_config_path (u_data_dir, MC_USERCONF_DIR, error);
  173. g_free (u_data_dir);
  174. g_free (u_cache_dir);
  175. g_free (u_config_dir);
  176. /* This is the directory, where MC was installed, on Unix this is DATADIR */
  177. /* and can be overriden by the MC_DATADIR environment variable */
  178. mc_datadir = g_getenv ("MC_DATADIR");
  179. if (mc_datadir != NULL)
  180. mc_global.sysconfig_dir = g_strdup (mc_datadir);
  181. else
  182. mc_global.sysconfig_dir = g_strdup (SYSCONFDIR);
  183. mc_global.share_data_dir = g_strdup (DATADIR);
  184. xdg_vars_initialized = TRUE;
  185. }
  186. /* --------------------------------------------------------------------------------------------- */
  187. void
  188. mc_config_deinit_config_paths (void)
  189. {
  190. if (!xdg_vars_initialized)
  191. return;
  192. g_free (xdg_config);
  193. g_free (xdg_cache);
  194. g_free (xdg_data);
  195. g_free (mc_global.share_data_dir);
  196. g_free (mc_global.sysconfig_dir);
  197. xdg_vars_initialized = FALSE;
  198. }
  199. /* --------------------------------------------------------------------------------------------- */
  200. const char *
  201. mc_config_get_data_path (void)
  202. {
  203. if (!xdg_vars_initialized)
  204. mc_config_init_config_paths (NULL);
  205. return (const char *) xdg_data;
  206. }
  207. /* --------------------------------------------------------------------------------------------- */
  208. const char *
  209. mc_config_get_cache_path (void)
  210. {
  211. if (!xdg_vars_initialized)
  212. mc_config_init_config_paths (NULL);
  213. return (const char *) xdg_cache;
  214. }
  215. /* --------------------------------------------------------------------------------------------- */
  216. const char *
  217. mc_config_get_home_dir (void)
  218. {
  219. if (homedir == NULL)
  220. {
  221. homedir = g_getenv ("HOME");
  222. if (homedir == NULL)
  223. homedir = g_get_home_dir ();
  224. }
  225. return homedir;
  226. }
  227. /* --------------------------------------------------------------------------------------------- */
  228. const char *
  229. mc_config_get_path (void)
  230. {
  231. if (!xdg_vars_initialized)
  232. mc_config_init_config_paths (NULL);
  233. return (const char *) xdg_config;
  234. }
  235. /* --------------------------------------------------------------------------------------------- */
  236. void
  237. mc_config_migrate_from_old_place (GError ** error)
  238. {
  239. char *old_dir;
  240. size_t rule_index;
  241. old_dir = mc_config_get_deprecated_path ();
  242. g_free (mc_config_init_one_config_path (xdg_config, EDIT_DIR, error));
  243. g_free (mc_config_init_one_config_path (xdg_cache, EDIT_DIR, error));
  244. g_free (mc_config_init_one_config_path (xdg_data, EDIT_DIR, error));
  245. for (rule_index = 0; mc_config_migrate_rules[rule_index].old_filename != NULL; rule_index++)
  246. {
  247. char *old_name;
  248. old_name =
  249. g_build_filename (old_dir, mc_config_migrate_rules[rule_index].old_filename, NULL);
  250. if (g_file_test (old_name, G_FILE_TEST_EXISTS))
  251. {
  252. char *new_name;
  253. new_name = g_build_filename (*mc_config_migrate_rules[rule_index].new_basedir,
  254. mc_config_migrate_rules[rule_index].new_filename, NULL);
  255. mc_config_copy (old_name, new_name, error);
  256. g_free (new_name);
  257. }
  258. g_free (old_name);
  259. }
  260. g_propagate_error (error,
  261. g_error_new (MC_ERROR, 0,
  262. _
  263. ("Your old settings were migrated from %s\n"
  264. "to Freedesktop recommended dirs.\n"
  265. "To get more info, please visit\n"
  266. "http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html"),
  267. old_dir));
  268. g_free (old_dir);
  269. }
  270. /* --------------------------------------------------------------------------------------------- */
  271. gboolean
  272. mc_config_deprecated_dir_present (void)
  273. {
  274. char *old_dir;
  275. gboolean is_present;
  276. old_dir = mc_config_get_deprecated_path ();
  277. is_present = g_file_test (old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
  278. g_free (old_dir);
  279. return is_present && !config_dir_present;
  280. }
  281. /* --------------------------------------------------------------------------------------------- */