commit 22fa09fcf9ba0974db3e6ea041237be73eed3308 Author: phantomjinx <p.g.richard...@phantomjinx.co.uk> Date: Sun Oct 30 20:16:34 2011 +0000
Avoid possibility of symlinks causing infinite loops * Possibility that when recursing directories, adding tracks, symlinks can cause an inifinite loop leaving application unusable. * Remedies this possibility by logging the directories processed and handling the targets of symlinks appropriately. * Fixes 2561965 - Infinite loop while adding folders with symlinks libgtkpod/file.c | 45 +++++++++++++++++++++++++++++++++-- libgtkpod/misc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libgtkpod/misc.h | 3 ++ 3 files changed, 113 insertions(+), 3 deletions(-) --- diff --git a/libgtkpod/file.c b/libgtkpod/file.c index caa431b..6551145 100644 --- a/libgtkpod/file.c +++ b/libgtkpod/file.c @@ -393,7 +393,10 @@ GSList* sort_tracknames_list(GSList *names) { * * \*------------------------------------------------------------------*/ -static void recurse_directories(gchar *name, GSList **trknames, gboolean descend) { +/* + * Internal function called by recurse_directories_with_history + */ +static void recurse_directories_internal(gchar *name, GSList **trknames, gboolean descend, GHashTable **directories_seen) { if (g_file_test(name, G_FILE_TEST_IS_DIR)) { GDir *dir = g_dir_open(name, 0, NULL); if (dir != NULL) { @@ -402,8 +405,28 @@ static void recurse_directories(gchar *name, GSList **trknames, gboolean descend next = g_dir_read_name(dir); if (next != NULL) { gchar *nextfull = g_build_filename(name, next, NULL); + + if (g_file_test(nextfull, G_FILE_TEST_IS_SYMLINK)) { + /* + * Need to check symlinks don't point to another directory that + * we have already dealt with, avoiding infinite loops. + */ + gchar* basepath = convert_symlink_to_absolute_path(name, nextfull); + if (!basepath) { + g_free(nextfull); + return; + } + + nextfull = basepath; + } + + if (g_hash_table_lookup(*directories_seen, nextfull)) + continue; + else + g_hash_table_insert(*directories_seen, nextfull, nextfull); + if (descend || !g_file_test(nextfull, G_FILE_TEST_IS_DIR)) { - recurse_directories(nextfull, trknames, descend); + recurse_directories_internal(nextfull, trknames, descend, directories_seen); } g_free(nextfull); } @@ -418,6 +441,22 @@ static void recurse_directories(gchar *name, GSList **trknames, gboolean descend } } +/* + * Recurse directories from @dir, adding filenames to @trknames. + * + * To avoid infinite loops due to symlinks, a directories hash is + * used to record visited sub-directories. + * + * @dir: root directory from which to retrieve filenames + * @trknames: list populated with filenames + * @descend: TRUE: add recursively + * FALSE: don't enter subdirectories + */ +static void recurse_directories_with_history(gchar *dir, GSList **trknames, gboolean descend) { + GHashTable *directories = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + recurse_directories_internal(dir, trknames, descend, &directories); + g_hash_table_destroy(directories); +} /* * Add all files in directory and subdirectories. @@ -446,7 +485,7 @@ gint add_directory_by_name(iTunesDB *itdb, gchar *name, Playlist *plitem, gboole block_widgets(); - recurse_directories(name, &trknames, descend); + recurse_directories_with_history(name, &trknames, descend); trknames = sort_tracknames_list(trknames); diff --git a/libgtkpod/misc.c b/libgtkpod/misc.c index bd5b757..8cb260b 100644 --- a/libgtkpod/misc.c +++ b/libgtkpod/misc.c @@ -1804,3 +1804,71 @@ void gtkpod_shutdown() { call_script("gtkpod.out", NULL); } +/** + * Convert the relative path @relpath to an absolute path using + * @basepath as the basis for deriving the new path. + * + * Essentially, removes any '.' and '..' from the relative path then + * concatenates the remaining path to the base path. + * + */ +gchar *convert_relative_to_absolute_path(gchar *basepath, gchar *relpath) { + if (g_path_is_absolute(relpath)) + return relpath; + + gchar *currdir = g_strconcat(".", G_DIR_SEPARATOR_S, NULL); + gchar *parentdir = g_strconcat("..", G_DIR_SEPARATOR_S, NULL); + gchar *abspath = NULL; + gchar *relsubpath = NULL; + + if (g_str_has_prefix(relpath, currdir)) { + if (strlen(relpath) > strlen(currdir)) { + relsubpath = relpath + strlen (currdir); + abspath = convert_relative_to_absolute_path(basepath, relsubpath); + } + else + abspath = basepath; + } + else if(g_str_has_prefix(relpath, parentdir)) { + gchar *baseparent = g_path_get_dirname(basepath); + + if (strlen(relpath) > strlen(parentdir)) { + relsubpath = relpath + strlen (parentdir); + abspath = convert_relative_to_absolute_path(baseparent, relsubpath); + } + else { + abspath = baseparent; + } + + g_free(baseparent); + } + else { + abspath = g_build_filename(basepath, relpath, NULL); + } + + g_free(parentdir); + g_free(currdir); + + return abspath; +} + +/** + * Reads the target of a symlink and returns the appropriate path. + * + * If the target is absolute then this is returned. + * + * If the target is relative then an absolute path derived from @basepath + * is returned. + * + */ +gchar *convert_symlink_to_absolute_path(gchar *basepath, gchar *symlink) { + gchar *sympath = g_file_read_link(symlink, NULL); + if (!sympath) + return NULL; + + if (g_path_is_absolute(sympath)) + return sympath; + else + return convert_relative_to_absolute_path(basepath, sympath); +} + diff --git a/libgtkpod/misc.h b/libgtkpod/misc.h index 8455ef1..ab3ba61 100644 --- a/libgtkpod/misc.h +++ b/libgtkpod/misc.h @@ -229,4 +229,7 @@ void message_sb_no_ipod_itdb_selected (); void gtkpod_shutdown (); +gchar *convert_relative_to_absolute_path(gchar *basepath, gchar *relpath); +gchar *convert_symlink_to_absolute_path(gchar *basepath, gchar *symlink); + #endif ------------------------------------------------------------------------------ Get your Android app more play: Bring it to the BlackBerry PlayBook in minutes. BlackBerry App World™ now supports Android™ Apps for the BlackBerry® PlayBook™. Discover just how easy and simple it is! http://p.sf.net/sfu/android-dev2dev _______________________________________________ gtkpod-cvs2 mailing list gtkpod-cvs2@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2