commit 22fa09fcf9ba0974db3e6ea041237be73eed3308
Author: phantomjinx <[email protected]>
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2