talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit ee15052fff7c3394e0121c3b523d4691708a6ab1
parent fa93b1c280c712db87a14061732940891cc7c5aa
Author: Colin Leroy <colin@colino.net>
Date:   Sat,  1 Dec 2012 21:03:48 +0000

2012-12-01 [colin]	3.9.0cvs34

	* src/common/utils.c
	* src/common/utils.h
		Add a canonicalizer function and use it to
		canonicalize rc_dir.

Diffstat:
MChangeLog | 7+++++++
MPATCHSETS | 1+
Mconfigure.ac | 2+-
Msrc/common/utils.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/common/utils.h | 1+
5 files changed, 157 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,10 @@ +2012-12-01 [colin] 3.9.0cvs34 + + * src/common/utils.c + * src/common/utils.h + Add a canonicalizer function and use it to + canonicalize rc_dir. + 2012-11-30 [mones] 3.9.0cvs33 * src/common/plugin.c diff --git a/PATCHSETS b/PATCHSETS @@ -4531,3 +4531,4 @@ ( cvs diff -u -r 1.274.2.360 -r 1.274.2.361 src/mainwindow.c; cvs diff -u -r 1.39.2.66 -r 1.39.2.67 src/mainwindow.h; cvs diff -u -r 1.150.2.132 -r 1.150.2.133 src/procmsg.c; cvs diff -u -r 1.17.2.66 -r 1.17.2.67 src/send_message.c; cvs diff -u -r 1.1.4.13 -r 1.1.4.14 src/send_message.h; cvs diff -u -r 1.43.2.133 -r 1.43.2.134 src/toolbar.c; cvs diff -u -r 1.19.2.35 -r 1.19.2.36 src/toolbar.h; ) > 3.9.0cvs31.patchset ( cvs diff -u -r 1.274.2.361 -r 1.274.2.362 src/mainwindow.c; cvs diff -u -r 1.39.2.67 -r 1.39.2.68 src/mainwindow.h; cvs diff -u -r 1.395.2.459 -r 1.395.2.460 src/summaryview.c; cvs diff -u -r 1.43.2.134 -r 1.43.2.135 src/toolbar.c; ) > 3.9.0cvs32.patchset ( cvs diff -u -r 1.13.2.47 -r 1.13.2.48 src/common/plugin.c; ) > 3.9.0cvs33.patchset +( cvs diff -u -r 1.36.2.209 -r 1.36.2.210 src/common/utils.c; cvs diff -u -r 1.20.2.83 -r 1.20.2.84 src/common/utils.h; ) > 3.9.0cvs34.patchset diff --git a/configure.ac b/configure.ac @@ -12,7 +12,7 @@ MINOR_VERSION=9 MICRO_VERSION=0 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=33 +EXTRA_VERSION=34 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/common/utils.c b/src/common/utils.c @@ -1874,21 +1874,26 @@ const gchar *get_rc_dir(void) void set_rc_dir(const gchar *dir) { + gchar *canonical_dir; if (claws_rc_dir != NULL) { g_print("Error: rc_dir already set\n"); } else { - rc_dir_alt = TRUE; - if (g_path_is_absolute(dir)) - claws_rc_dir = g_strdup(dir); - else { - claws_rc_dir = g_strconcat(g_get_current_dir(), - G_DIR_SEPARATOR_S, dir, NULL); + int err = cm_canonicalize_filename(dir, &canonical_dir); + if (err) { + g_print("Error looking for %s: %d(%s)\n", + dir, -err, strerror(-err)); + exit(0); } + rc_dir_alt = TRUE; + + claws_rc_dir = canonical_dir; + debug_print("set rc_dir to %s\n", claws_rc_dir); if (!is_dir_exist(claws_rc_dir)) { if (make_dir_hier(claws_rc_dir) != 0) { g_print("Error: can't create %s\n", claws_rc_dir); + exit(0); } } } @@ -5346,3 +5351,139 @@ void cm_mutex_free(GMutex *mutex) { g_mutex_free(mutex); #endif } + +static gchar *canonical_list_to_file(GSList *list) +{ + GString *result = g_string_new(NULL); + GSList *pathlist = g_slist_reverse(g_slist_copy(list)); + GSList *cur; + gchar *str; + + result = g_string_append(result, G_DIR_SEPARATOR_S); + + for (cur = pathlist; cur; cur = cur->next) { + result = g_string_append(result, (gchar *)cur->data); + if (cur->next) + result = g_string_append(result, G_DIR_SEPARATOR_S); + } + g_slist_free(pathlist); + + str = result->str; + g_string_free(result, FALSE); + + return str; +} + +static GSList *cm_split_path(const gchar *filename, int depth) +{ + gchar **path_parts; + GSList *canonical_parts = NULL; + struct stat st; + int i; + gboolean follow_symlinks = TRUE; + + if (depth > 32) { + errno = ELOOP; + return NULL; + } + + if (!g_path_is_absolute(filename)) { + errno =EINVAL; + return NULL; + } + + path_parts = g_strsplit(filename, G_DIR_SEPARATOR_S, -1); + + for (i = 0; path_parts[i] != NULL; i++) { + if (!strcmp(path_parts[i], "")) + continue; + if (!strcmp(path_parts[i], ".")) + continue; + else if (!strcmp(path_parts[i], "..")) { + if (i == 0) { + errno =ENOTDIR; + return NULL; + } + else /* Remove the last inserted element */ + canonical_parts = + g_slist_delete_link(canonical_parts, + canonical_parts); + } else { + gchar *tmp_path; + + canonical_parts = g_slist_prepend(canonical_parts, + g_strdup(path_parts[i])); + + tmp_path = canonical_list_to_file(canonical_parts); + + if(g_stat(tmp_path, &st) < 0) { + if (errno == ENOENT) { + errno = 0; + follow_symlinks = FALSE; + } + if (errno != 0) { + g_free(tmp_path); + slist_free_strings_full(canonical_parts); + g_strfreev(path_parts); + + return NULL; + } + } + if (follow_symlinks && g_file_test(tmp_path, G_FILE_TEST_IS_SYMLINK)) { + GError *error = NULL; + gchar *target = g_file_read_link(tmp_path, &error); + + slist_free_strings_full(canonical_parts); + canonical_parts = NULL; + if (!error) + canonical_parts = cm_split_path(target, depth + 1); + else + g_error_free(error); + if (canonical_parts == NULL) { + g_free(tmp_path); + g_strfreev(path_parts); + return NULL; + } + g_free(target); + } + g_free(tmp_path); + } + } + g_strfreev(path_parts); + return canonical_parts; +} + +/* + * Canonicalize a filename, resolving symlinks along the way. + * Returns a negative errno in case of error. + */ +int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name) { + GSList *canonical_parts; + gboolean is_absolute; + + if (filename == NULL) + return -EINVAL; + if (canonical_name == NULL) + return -EINVAL; + *canonical_name = NULL; + + is_absolute = g_path_is_absolute(filename); + if (!is_absolute) { + /* Always work on absolute filenames. */ + gchar *cur = g_get_current_dir(); + gchar *absolute_filename = g_strconcat(cur, G_DIR_SEPARATOR_S, + filename, NULL); + + canonical_parts = cm_split_path(absolute_filename, 0); + g_free(absolute_filename); + g_free(cur); + } else + canonical_parts = cm_split_path(filename, 0); + + if (canonical_parts == NULL) + return -errno; + + *canonical_name = canonical_list_to_file(canonical_parts); + slist_free_strings_full(canonical_parts); + return 0; +} diff --git a/src/common/utils.h b/src/common/utils.h @@ -591,6 +591,7 @@ int claws_unlink(const gchar *filename); GMutex *cm_mutex_new(void); void cm_mutex_free(GMutex *mutex); +int cm_canonicalize_filename(const gchar *filename, gchar **canonical_name); #ifdef __cplusplus } #endif