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&#153; now supports Android&#153; Apps 
for the BlackBerry&reg; PlayBook&#153;. 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

Reply via email to