aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog11
-rw-r--r--camel/providers/local/camel-maildir-store.c95
2 files changed, 80 insertions, 26 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 2047c2d5ec..564238a3bc 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,5 +1,16 @@
2001-09-10 <NotZed@Ximian.com>
+ * providers/local/camel-maildir-store.c (get_folder_info): Pass in
+ a hashtalbe used for finding visited nodes.
+ (inode_hash):
+ (inode_equal):
+ (inode_free): Helper functions for visited node checks, hashes on
+ inode + device number.
+ (scan_dir): Dont re-visited directories we've already visited, use
+ inodes + device number.
+ Also, if the folder doesn't contain cur/tmp/new, mark it as
+ noselect, but continue to recurse folders, if asked.
+
* camel-folder.c (move_messages_to): Progress reporting while
moving messages.
diff --git a/camel/providers/local/camel-maildir-store.c b/camel/providers/local/camel-maildir-store.c
index 290f91a90b..c200058c95 100644
--- a/camel/providers/local/camel-maildir-store.c
+++ b/camel/providers/local/camel-maildir-store.c
@@ -226,7 +226,14 @@ static CamelFolderInfo *camel_folder_info_new(const char *url, const char *full,
return fi;
}
-static int scan_dir(char *root, const char *path, guint32 flags, CamelFolderInfo *parent, CamelFolderInfo **fip, CamelException *ex)
+/* used to find out where we've visited already */
+struct _inode {
+ dev_t dnode;
+ ino_t inode;
+};
+
+/* returns number of records found at or below this level */
+static int scan_dir(GHashTable *visited, char *root, const char *path, guint32 flags, CamelFolderInfo *parent, CamelFolderInfo **fip, CamelException *ex)
{
DIR *dir;
struct dirent *d;
@@ -246,30 +253,32 @@ static int scan_dir(char *root, const char *path, guint32 flags, CamelFolderInfo
if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)
&& stat(cur, &st) == 0 && S_ISDIR(st.st_mode)
- && stat(new, &st) == 0 && S_ISDIR(st.st_mode)) {
+ && stat(new, &st) == 0 && S_ISDIR(st.st_mode))
uri = g_strdup_printf("maildir://%s#%s", root, path);
- base = strrchr(path, '/');
- if (base)
- base++;
- else
- base = path;
- fi = camel_folder_info_new(uri, path, base, -1);
-
- printf("found! uri = %s\n", fi->url);
- printf(" full_name = %s\n name = '%s'\n", fi->full_name, fi->name);
-
- fi->parent = parent;
- fi->sibling = *fip;
- *fip = fi;
- g_free(uri);
- }
+ else
+ uri = g_strdup_printf("maildir://%s;noselect=yes#%s", root, path);
+
+ base = strrchr(path, '/');
+ if (base)
+ base++;
+ else
+ base = path;
+ fi = camel_folder_info_new(uri, path, base, -1);
+
+ printf("found! uri = %s\n", fi->url);
+ printf(" full_name = %s\n name = '%s'\n", fi->full_name, fi->name);
+
+ fi->parent = parent;
+ fi->sibling = *fip;
+ *fip = fi;
+ g_free(uri);
g_free(tmp);
g_free(cur);
g_free(new);
- /* we only look further if we found one at this level */
- if (fi && ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) || parent == NULL)) {
+ /* always look further if asked */
+ if (((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) || parent == NULL)) {
dir = opendir(name);
if (dir == NULL) {
camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
@@ -289,12 +298,21 @@ static int scan_dir(char *root, const char *path, guint32 flags, CamelFolderInfo
tmp = g_strdup_printf("%s/%s", name, d->d_name);
if (stat(tmp, &st) == 0 && S_ISDIR(st.st_mode)) {
- new = g_strdup_printf("%s/%s", path, d->d_name);
- if (scan_dir(root, new, flags, fi, &fi->child, ex) == -1) {
- g_free(tmp);
- g_free(new);
- closedir(dir);
- return -1;
+ struct _inode in = { st.st_dev, st.st_ino };
+
+ /* see if we've visited already */
+ if (g_hash_table_lookup(visited, &in) == NULL) {
+ struct _inode *inew = g_malloc(sizeof(*inew));
+
+ *inew = in;
+ g_hash_table_insert(visited, inew, inew);
+ new = g_strdup_printf("%s/%s", path, d->d_name);
+ if (scan_dir(visited, root, new, flags, fi, &fi->child, ex) == -1) {
+ g_free(tmp);
+ g_free(new);
+ closedir(dir);
+ return -1;
+ }
}
g_free(new);
}
@@ -308,16 +326,41 @@ static int scan_dir(char *root, const char *path, guint32 flags, CamelFolderInfo
return 0;
}
+static guint inode_hash(const void *d)
+{
+ const struct _inode *v = d;
+
+ return v->inode ^ v->dnode;
+}
+
+static gboolean inode_equal(const void *a, const void *b)
+{
+ const struct _inode *v1 = a, *v2 = b;
+
+ return v1->inode == v2->inode && v1->dnode == v2->dnode;
+}
+
+static void inode_free(void *k, void *v, void *d)
+{
+ g_free(k);
+}
+
static CamelFolderInfo *
get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
{
CamelFolderInfo *fi = NULL;
CamelService *service = (CamelService *)store;
+ GHashTable *visited;
+
+ visited = g_hash_table_new(inode_hash, inode_equal);
- if (scan_dir(service->url->path, top?top:".", flags, NULL, &fi, ex) == -1 && fi != NULL) {
+ if (scan_dir(visited, service->url->path, top?top:".", flags, NULL, &fi, ex) == -1 && fi != NULL) {
camel_store_free_folder_info_full(store, fi);
fi = NULL;
}
+ g_hash_table_foreach(visited, inode_free, NULL);
+ g_hash_table_destroy(visited);
+
return fi;
}