diff --git a/apps/SOURCES b/apps/SOURCES
index 53a67fd..10bb3dd 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -87,6 +87,7 @@ gui/pitchscreen.c
 #ifdef HAVE_QUICKSCREEN
 gui/quickscreen.c
 #endif
+gui/tagcache_config.c
 
 gui/wps.c
 gui/scrollbar.c
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 09a66f3..500ed82 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -152,9 +152,11 @@ void list_draw(struct screen *display, struct gui_synclist *list)
     int icon_yoffset = 0; /* to center the icon */
     bool show_title;
     struct viewport *list_text_vp = &list_text[screen];
-
+    int indent = 0;
+    int char_width;
     line_height = parent->line_height;
     display->set_viewport(parent);
+    char_width = display->getstringsize("M", NULL, NULL);
     display->clear_viewport();
     display->scroll_stop(list_text_vp);
     *list_text_vp = *parent;
@@ -247,9 +249,29 @@ void list_draw(struct screen *display, struct gui_synclist *list)
         unsigned char *entry_name;
         int text_pos = 0;
         int line = i - start;
+        indent = 0;
         s = list->callback_get_item_name(i, list->data, entry_buffer,
                                          sizeof(entry_buffer));
         entry_name = P2STR(s);
+        while (*entry_name == '\t')
+        {
+            indent++;
+            entry_name++;
+        }
+        if (indent)
+        {
+            if (icon_width)
+                indent *= icon_width;
+            else
+                indent *= char_width;
+        }
+        if (indent)
+        {
+            list_icons.x += indent;
+            list_text_vp->x += indent;
+            list_text_vp->width -= indent;
+        }
+            
         display->set_viewport(list_text_vp);
         style = STYLE_DEFAULT;
         /* position the string at the correct offset place */
@@ -351,6 +373,12 @@ void list_draw(struct screen *display, struct gui_synclist *list)
                             line*line_height + draw_offset + icon_yoffset,
                             Icon_Cursor);
         }
+        if (indent)
+        {
+            list_icons.x -= indent;
+            list_text_vp->x -= indent;
+            list_text_vp->width += indent;
+        }
     }
     display->set_viewport(parent);
     display->update_viewport();
diff --git a/apps/gui/tagcache_config.c b/apps/gui/tagcache_config.c
new file mode 100644
index 0000000..9124261
--- /dev/null
+++ b/apps/gui/tagcache_config.c
@@ -0,0 +1,392 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ *
+ * Copyright (C) 2011 Jonathan Gordon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "inttypes.h"
+#include "config.h"
+#include "core_alloc.h"
+#include "filetypes.h"
+#include "lang.h"
+#include "language.h"
+#include "list.h"
+#include "plugin.h"
+#include "tagcache.h"
+
+
+/*
+ * Order for changing child states:
+ * 1) expand folder (skip to 2 if empty)
+ * 2) collapse and select
+ * 3) unselect
+ */
+
+enum child_state {
+    EXPANDED,
+    SELECTED,
+    COLLAPSED
+};
+    
+
+struct child {
+    char* name;
+    struct folder *folder;
+    enum child_state state;
+};
+
+struct folder {
+    char *name;
+    struct child *children;
+    int children_count;
+    int depth;
+
+    struct folder* previous;
+};
+
+static char *buffer_front, *buffer_end;
+static char* folder_alloc(size_t size)
+{
+    char* retval;
+    /* 32-bit aligned */
+    size = (size + 3) & ~3;
+    if (buffer_front + size > buffer_end)
+    {
+        return NULL;
+    }
+    retval = buffer_front;
+    buffer_front += size;
+    return retval;
+}
+static char* folder_alloc_from_end(size_t size)
+{
+    if (buffer_end - size < buffer_front)
+    {
+        return NULL;
+    }
+    buffer_end -= size;
+    return buffer_end;
+}
+    
+
+static char* get_full_path(struct folder *start)
+{
+    static char buffer[MAX_PATH];
+    char *buf = &buffer[MAX_PATH-1];
+    int remaining = MAX_PATH-1;
+    struct folder *this = start;
+    if (start == NULL)
+        return "/";
+    buf[0] = '\0';
+    buf--;
+    remaining--;
+    while (this)
+    {
+        int len = strlen(this->name);
+        if (len + 1 > remaining)
+            return NULL;
+        buf -= len + 1;
+        memcpy(buf, this->name, len);
+        buf[len] = '/';
+        this = this->previous;
+    }
+    if (remaining < 1)
+        return NULL;
+    /* remove the trailing / */
+    buf[strlen(buf)-1] = '\0';
+    return buf;
+}
+/* support function for qsort() */
+static int compare(const void* p1, const void* p2)
+{
+    struct child *left = (struct child*)p1;
+    struct child *right = (struct child*)p2;
+    return strcasecmp(left->name, right->name);
+}
+
+static struct folder* load_folder(struct folder* parent, char *folder)
+{
+    DIR *dir;
+    char* path = get_full_path(parent);
+    char fullpath[MAX_PATH];
+    struct dirent *entry;
+    struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
+    int child_count = 0;
+    char *first_child = NULL;
+
+    snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder);
+    
+    if (!this)
+        return NULL;
+    dir = opendir(fullpath);
+    if (!dir)
+        return NULL;
+    this->previous = parent;
+    this->name = folder;
+    this->children = NULL;
+    this->children_count = 0;
+    this->depth = parent ? parent->depth + 1 : -1;
+    
+    while ((entry = readdir(dir))) {
+        int len = strlen((char *)entry->d_name);
+        struct dirinfo info;
+
+        info = dir_get_info(dir, entry);
+
+        /* skip anything not a directory */
+        if ((info.attribute & ATTR_DIRECTORY) == 0) {
+            continue;
+        }
+        /* skip directories . and .. */
+        if ((((len == 1) && (!strncmp((char *)entry->d_name, ".", 1))) ||
+             ((len == 2) && (!strncmp((char *)entry->d_name, "..", 2))))) {
+            continue;
+        }
+        char *name = folder_alloc_from_end(len+1);
+        if (!name)
+            return NULL;
+        memcpy(name, (char *)entry->d_name, len+1);
+        child_count++;
+        first_child = name;
+    }
+    closedir(dir);
+    /* now put the names in the array */
+    this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count);
+    if (!this->children)
+        return NULL;
+    while (child_count)
+    {
+        this->children[this->children_count].name = first_child;
+        this->children[this->children_count].folder = NULL;
+        this->children[this->children_count].state = COLLAPSED;
+        this->children_count++;
+        first_child += strlen(first_child) + 1;
+        child_count--;
+    }
+    qsort(this->children, this->children_count, sizeof(struct child), compare);
+    return this;
+}
+
+static int count_items(struct folder *start)
+{
+    int count = 0;
+    int i;
+
+    for (i=0; i<start->children_count; i++)
+    {
+        struct child *foo = &start->children[i];
+        if (foo->state == EXPANDED)
+            count += count_items(foo->folder);
+        count++;
+    }
+    return count;
+}    
+
+static struct child* find_index(struct folder *start, int index, struct folder **parent)
+{
+    int i = 0;
+    while (i < start->children_count)
+    {
+        struct child *foo = &start->children[i];
+        if (i == index)
+        {
+            *parent = start;
+            return foo;
+        }
+        i++;
+        if (foo->state == EXPANDED)
+        {
+            struct child *bar = find_index(foo->folder, index - i, parent);
+            if (bar)
+            {
+                return bar;
+            }
+            index -= count_items(foo->folder);
+        }
+    }
+    return NULL;
+}
+
+static const char * folder_get_name(int selected_item, void * data,
+                                   char * buffer, size_t buffer_len)
+{
+    (void)buffer_len;
+    struct folder *root = (struct folder*)data;
+    struct folder *parent = NULL;
+    struct child *this = find_index(root, selected_item, &parent);
+    
+    buffer[0] = '\0';
+    if (parent->depth >= 0)
+    {
+        int i = 0;
+        while (i < parent->depth + 1)
+        {
+            strcat(buffer, "\t");
+            i++;
+        }
+    }
+    strcat(buffer, this->name);
+    return buffer;
+}
+
+static enum themable_icons folder_get_icon(int selected_item, void * data)
+{
+    struct folder *root = (struct folder*)data;
+    struct folder *parent = NULL;
+    struct child *this = find_index(root, selected_item, &parent);
+
+    switch (this->state)
+    {
+        case SELECTED:
+            return Icon_Cursor;
+        case COLLAPSED:
+            return Icon_Folder;
+        case EXPANDED:
+            return Icon_Submenu;
+    }
+    return Icon_NOICON;
+}
+
+static int folder_action_callback(int action, struct gui_synclist *list)
+{
+    struct folder *root = (struct folder*)list->data;
+    if (action == ACTION_STD_OK)
+    {
+        struct folder *parent = NULL;
+        struct child *this = find_index(root, list->selected_item, &parent);        
+        switch (this->state)
+        {
+            case EXPANDED:
+                this->state = SELECTED;
+                break;
+            case SELECTED:
+                this->state = COLLAPSED;
+                if (this->folder && this->folder->children_count == 0)
+                    this->state = COLLAPSED;
+                break;
+            case COLLAPSED:
+                if (this->folder == NULL)
+                    this->folder = load_folder(parent, this->name);
+                this->state = this->folder->children_count == 0 ?
+                        SELECTED : EXPANDED;
+        }
+        list->nb_items = count_items(root);
+        return ACTION_REDRAW;
+    }
+    return action;
+}
+
+static struct child* find_from_filename(char* filename, struct folder *root)
+{
+    char *slash = strchr(filename, '/');
+    int i = 0;
+    if (slash)
+        *slash = '\0';
+    if (!root)
+        return NULL;
+
+    while (i < root->children_count)
+    {
+        struct child *this = &root->children[i];
+        if (!strcasecmp(this->name, filename))
+        {
+            if (!slash)
+                return this;
+            if (!this->folder)
+                this->folder = load_folder(root, this->name);
+            this->state = EXPANDED;
+            return find_from_filename(slash+1, this->folder);
+        }
+        i++;
+    }
+    return NULL;
+}
+
+static int readline_callback(int n, char *buf, void *parameters)
+{
+    (void)n;
+    struct folder *root = (struct folder*)parameters;
+    char* slash = strchr(buf, '/');
+    struct child *item = find_from_filename(slash ? slash + 1 : buf, root);
+    if (item)
+        item->state = SELECTED;
+    return 0;
+}
+
+static void save_folders(struct folder *root, int fd)
+{
+    int i = 0;
+
+    while (i < root->children_count)
+    {
+        struct child *this = &root->children[i];
+        if (this->state == SELECTED)
+        {
+            if (this->folder)
+                snprintf(buffer_front, buffer_end - buffer_front,
+                        "%s\n", get_full_path(this->folder));
+            else
+                snprintf(buffer_front, buffer_end - buffer_front,
+                        "%s/%s\n", get_full_path(root), this->name);
+            write(fd, buffer_front, strlen(buffer_front));
+        }
+        else if (this->state == EXPANDED)
+            save_folders(this->folder, fd);
+        i++;
+    }
+}
+        
+
+bool tagcache_do_config(void)
+{
+    struct folder *root;
+    struct simplelist_info info;
+    size_t buf_size;
+    int fd;
+    char buf[512];
+
+    buffer_front = plugin_get_buffer(&buf_size);
+    buffer_end = buffer_front + buf_size;
+    root = load_folder(NULL, "");
+    
+    fd = open_utf8(TAGCACHE_SEARCHROOTS, O_RDONLY);
+    if (fd >= 0)
+    {
+        fast_readline(fd, buf, sizeof buf, root, readline_callback);
+        close(fd);
+    }
+
+    simplelist_info_init(&info, str(LANG_SELECT_DATABASE_DIRS),
+            count_items(root), root);
+    info.get_name = folder_get_name;
+    info.action_callback = folder_action_callback;
+    info.get_icon = folder_get_icon;
+    simplelist_show_list(&info);
+    if (yesno_pop(ID2P(LANG_SAVE_CHANGES)))
+    {
+        fd = open_utf8(TAGCACHE_SEARCHROOTS, O_CREAT|O_TRUNC|O_RDWR);
+        if (fd >= 0)
+        {
+            save_folders(root, fd);
+            close(fd);
+            return count_items(root) > 0;
+        }
+    }
+    return false;
+}
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 627fda8..083c870 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -12993,3 +12993,17 @@
     *: "Restart Sleep Timer On Keypress"
   </voice>
 </phrase>
+<phrase>
+  id: LANG_SELECT_DATABASE_DIRS
+  desc: in settings_menu
+  user: core
+  <source>
+    *: "Select directories to scan"
+  </source>
+  <dest>
+    *: "Select directories to scan"
+  </dest>
+  <voice>
+    *: "Select directories to scan"
+  </voice>
+</phrase>
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 659a7f2..608fb6f 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -65,6 +65,21 @@ static void tagcache_update_with_splash(void)
     splash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH));
 }
 
+bool tagcache_do_config(void);
+static int dirs_to_scan(void)
+{
+    if (tagcache_do_config())
+    {
+        static const char *lines[] = {ID2P(LANG_TAGCACHE_BUSY),
+                                      ID2P(LANG_TAGCACHE_FORCE_UPDATE)};
+        static const struct text_message message = {lines, 2};
+        
+        if (gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES)
+            tagcache_rebuild_with_splash();
+    }
+    return 0;
+}
+
 #ifdef HAVE_TC_RAMCACHE
 MENUITEM_SETTING(tagcache_ram, &global_settings.tagcache_ram, NULL);
 #endif
@@ -82,12 +97,17 @@ MENUITEM_FUNCTION(tc_export, 0, ID2P(LANG_TAGCACHE_EXPORT),
 MENUITEM_FUNCTION(tc_import, 0, ID2P(LANG_TAGCACHE_IMPORT),
                     (int(*)(void))tagtree_import, NULL,
                     NULL, Icon_NOICON);
+MENUITEM_FUNCTION(tc_paths, 0, ID2P(LANG_SELECT_DATABASE_DIRS),
+                    dirs_to_scan, NULL, NULL, Icon_NOICON);
+                    
 MAKE_MENU(tagcache_menu, ID2P(LANG_TAGCACHE), 0, Icon_NOICON,
 #ifdef HAVE_TC_RAMCACHE
                 &tagcache_ram,
 #endif
                 &tagcache_autoupdate, &tc_init, &tc_update, &runtimedb,
-                &tc_export, &tc_import);
+                &tc_export, &tc_import
+                ,&tc_paths
+                );
 #endif /* HAVE_TAGCACHE */
 /*    TAGCACHE MENU                */
 /***********************************/
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 747ba76..2bad0e6 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -189,10 +189,12 @@ static int browser(void* param)
                         stat->processed_entries == 0 && stat->commit_step == 0)
                     {
                         /* Prompt the user */
-                        reinit_attempted = true;
                         static const char *lines[]={
                             ID2P(LANG_TAGCACHE_BUSY), ID2P(LANG_TAGCACHE_FORCE_UPDATE)};
-                        static const struct text_message message={lines, 2};
+                        static const struct text_message message={lines, 2};                        
+                        reinit_attempted = true;
+                        if (!tagcache_do_config())
+                            break;
                         if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)
                             break;
                         FOR_NB_SCREENS(i)
diff --git a/apps/tagcache.c b/apps/tagcache.c
index ef642b1..5fa22e1 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -4272,10 +4272,27 @@ static void __attribute__ ((noinline)) check_ignore(const char *dirname,
     *unignore = file_exists(newpath);
 }
 
+#define MAX_STATIC_ROOTS 8
 static struct search_roots_ll {
     const char *path;
     struct search_roots_ll * next;
-} roots_ll;
+} roots_ll[MAX_STATIC_ROOTS];
+
+/* check if the path is already included in the search roots, by the
+ * means that the path itself or one of its parents folders is in the list */
+static bool search_root_exists(const char *path)
+{
+    struct search_roots_ll *this;
+    for(this = &roots_ll[0]; this; this = this->next)
+    {
+        size_t root_len = strlen(this->path);
+        /* check if the link target is inside of an existing search root
+         * don't add if target is inside, we'll scan it later */
+        if (!strncmp(this->path, path, root_len))
+            return true;
+    }
+    return false;
+}
 
 #ifdef APPLICATION
 /*
@@ -4316,14 +4333,11 @@ static bool add_search_root(const char *name)
     if (realpath(target, abs_target) == NULL)
         return false;
 
-    for(this = &roots_ll; this; prev = this, this = this->next)
-    {
-        size_t root_len = strlen(this->path);
-        /* check if the link target is inside of an existing search root
-         * don't add if target is inside, we'll scan it later */
-        if (!strncmp(this->path, abs_target, root_len))
-            return false;
-    }
+    if (search_root_exists(abs_target))
+        return false;
+
+    /* get the end of the list */
+    for(this = &roots_ll[0]; this; prev = this, this = this->next);
 
     if (prev)
     {
@@ -4347,14 +4361,22 @@ static bool add_search_root(const char *name)
     return false;
 }
 
+static int free_search_root_single(struct search_roots_ll * start)
+{
+    if (start < &roots_ll[0] && start >= &roots_ll[MAX_STATIC_ROOTS])
+    {
+        free(start->next);
+        return sizeof(struct search_roots_ll);
+    }
+    return 0;
+}
+
 static int free_search_roots(struct search_roots_ll * start)
 {
     int ret = 0;
     if (start->next)
     {
-        ret += free_search_roots(start->next);
-        ret += sizeof(struct search_roots_ll);
-        free(start->next);
+        ret += free_search_root_single(start->next);
     }
     return ret;
 }
@@ -4382,6 +4404,11 @@ static bool check_dir(const char *dirname, int add_files)
     /* don't do anything if both ignore and unignore are there */
     if (ignore != unignore)
         add_files = unignore;
+    if (ignore)
+    {
+        closedir(dir);
+        return true;
+    }
 
     /* Recursively scan the dir. */
 #ifdef __PCTOOL__
@@ -4412,7 +4439,7 @@ static bool check_dir(const char *dirname, int add_files)
 
         processed_dir_count++;
         if (info.attribute & ATTR_DIRECTORY)
-#ifndef SIMULATOR
+#if 0 //ifndef SIMULATOR
         {   /* don't follow symlinks to dirs, but try to add it as a search root
              * this makes able to avoid looping in recursive symlinks */
             if (info.attribute & ATTR_LINK)
@@ -4459,7 +4486,8 @@ void tagcache_screensync_enable(bool state)
     tc_stat.syncscreen = state;
 }
 
-void tagcache_build(const char *path)
+
+static void do_tagcache_build(const char *path[])
 {
     struct tagcache_header header;
     bool ret;
@@ -4501,17 +4529,29 @@ void tagcache_build(const char *path)
     write(cachefd, &header, sizeof(struct tagcache_header));
 
     ret = true;
-    roots_ll.path = path;
-    roots_ll.next = NULL;
+
+    roots_ll[0].path = path[0];
+    roots_ll[0].next = NULL;
+    /* i is for the path vector, j for the roots_ll array
+     * path can be skipped , but root_ll entries can't */
+    for(int i = 1, j = 1; path[i] && j < MAX_STATIC_ROOTS; i++)
+    {
+        if (search_root_exists(path[i])) /* skip this path */
+            continue;
+
+        roots_ll[j].path = path[i];
+        roots_ll[j-1].next = &roots_ll[j];
+        j++;
+    }
+
     struct search_roots_ll * this;
     /* check_dir might add new roots */
-    for(this = &roots_ll; this; this = this->next)
+    for(this = &roots_ll[0]; this; this = this->next)
     {
         strcpy(curpath, this->path);
         ret = ret && check_dir(this->path, true);
     }
-    if (roots_ll.next)
-        free_search_roots(roots_ll.next);
+    free_search_roots(&roots_ll[0]);
 
     /* Write the header. */
     header.magic = TAGCACHE_MAGIC;
@@ -4558,6 +4598,31 @@ void tagcache_build(const char *path)
     cpu_boost(false);
 }
 
+
+void tagcache_build(void)
+{
+    int fd = open_utf8(TAGCACHE_SEARCHROOTS, O_RDONLY);
+    char *vect[MAX_STATIC_ROOTS + 1]; /* +1 to ensure NULL sentinel */
+    char str[1024];
+    char *line = str;
+    int maxlen = 1024, count = 0;
+
+    if (fd >= 0)
+    {
+        while (read_line(fd, line, maxlen) > 0)
+        {
+            vect[count++] = line;
+            line -= strlen(line);
+            line += strlen(line);
+        }
+        close(fd);
+    }
+
+    vect[count] = NULL;
+
+    do_tagcache_build((const char**)vect);
+}
+
 #ifdef HAVE_TC_RAMCACHE
 static void load_ramcache(void)
 {
@@ -4643,11 +4708,11 @@ static void tagcache_thread(void)
             case Q_REBUILD:
                 remove_files();
                 remove(TAGCACHE_FILE_TEMP);
-                tagcache_build("/");
+                tagcache_build();
                 break;
             
             case Q_UPDATE:
-                tagcache_build("/");
+                tagcache_build();
 #ifdef HAVE_TC_RAMCACHE
                 load_ramcache();
 #endif
@@ -4665,13 +4730,13 @@ static void tagcache_thread(void)
                 {
                     load_ramcache();
                     if (tc_stat.ramcache && global_settings.tagcache_autoupdate)
-                        tagcache_build("/");
+                        tagcache_build();
                 }
                 else
 #endif
                 if (global_settings.tagcache_autoupdate)
                 {
-                    tagcache_build("/");
+                    tagcache_build();
                     
                     /* This will be very slow unless dircache is enabled
                        or target is flash based, but do it anyway for
diff --git a/apps/tagcache.h b/apps/tagcache.h
index 44161cf..6b23a96 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -99,6 +99,9 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
 /* Serialized DB. */
 #define TAGCACHE_STATEFILE       ROCKBOX_DIR "/database_state.tcd"
 
+/* DB search roots text file. */
+#define TAGCACHE_SEARCHROOTS       ROCKBOX_DIR "/database_roots.txt"
+
 /* Tag to be used on untagged files. */
 #define UNTAGGED "<Untagged>"
 
@@ -201,8 +204,6 @@ struct tagcache_search {
     int32_t idx_id;      /* Entry number in the master index. */
 };
 
-void tagcache_build(const char *path);
-
 #ifdef __PCTOOL__
 void tagcache_reverse_scan(void);
 #endif
