* mu-maildir.c: clear up maildir scanning

- improve handle of special dirs/files (add dovecot special-casing)
  - clear up struct direntry* mem management
This commit is contained in:
djcb
2012-03-19 20:46:17 +02:00
parent 159d26ee7d
commit 58ecdd78b7

View File

@ -55,10 +55,11 @@
* and return it in the d_type parameter * and return it in the d_type parameter
*/ */
#ifdef HAVE_STRUCT_DIRENT_D_TYPE #ifdef HAVE_STRUCT_DIRENT_D_TYPE
#define GET_DTYPE(DE,FP) \ #define GET_DTYPE(DE,FP) \
((DE)->d_type == DT_UNKNOWN ? mu_util_get_dtype_with_lstat((FP)) : (DE)->d_type) ((DE)->d_type == DT_UNKNOWN ? mu_util_get_dtype_with_lstat((FP)) : \
(DE)->d_type)
#else #else
#define GET_DTYPE(DE,FP) \ #define GET_DTYPE(DE,FP) \
mu_util_get_dtype_with_lstat((FP)) mu_util_get_dtype_with_lstat((FP))
#endif /*HAVE_STRUCT_DIRENT_D_TYPE*/ #endif /*HAVE_STRUCT_DIRENT_D_TYPE*/
@ -341,16 +342,23 @@ is_dotdir_to_ignore (const char* dir)
static gboolean static gboolean
ignore_dir_entry (struct dirent *entry, unsigned char d_type) ignore_dir_entry (struct dirent *entry, unsigned char d_type)
{ {
/* if it's not a dir and not a file, ignore it. if (G_LIKELY(d_type == DT_REG)) {
* note, this means also symlinks (DT_LNK) are ignored,
* maybe make this optional */
if (G_UNLIKELY(d_type != DT_REG && d_type != DT_DIR))
return TRUE;
/* ignore '.' and '..' dirs, as well as .notmuch and /* ignore dovecot metadata */
* .nnmaildir */ if (entry->d_name[0] == 'd' &&
strncmp (entry->d_name, "dovecot", 7) == 0)
return TRUE;
/* ignore core files */
if (entry->d_name[0] == 'c' &&
strncmp (entry->d_name, "core", 4) == 0)
return TRUE;
return is_dotdir_to_ignore (entry->d_name); return FALSE; /* other files: don't ignore */
} else if (d_type == DT_DIR)
return is_dotdir_to_ignore (entry->d_name);
else
return TRUE; /* ignore non-normal files, non-dirs */
} }
/* /*
@ -407,8 +415,9 @@ process_dir_entry (const char* path, const char* mdir, struct dirent *entry,
case DT_DIR: { case DT_DIR: {
char *my_mdir; char *my_mdir;
MuError rv; MuError rv;
/* my_mdir is the search maildir (the dir starting with the top-level /* my_mdir is the search maildir (the dir starting
* maildir as /, and without the /tmp, /cur, /new * with the top-level maildir as /, and without the
* /tmp, /cur, /new
*/ */
my_mdir = get_mdir_for_path (mdir, entry->d_name); my_mdir = get_mdir_for_path (mdir, entry->d_name);
rv = process_dir (fullpath, my_mdir, cb_msg, cb_dir, data); rv = process_dir (fullpath, my_mdir, cb_msg, cb_dir, data);
@ -423,22 +432,20 @@ process_dir_entry (const char* path, const char* mdir, struct dirent *entry,
} }
static const size_t DIRENT_ALLOC_SIZE =
offsetof (struct dirent, d_name) + PATH_MAX;
static struct dirent* static struct dirent*
dirent_copy (struct dirent *entry) dirent_new (void)
{ {
struct dirent *d; return (struct dirent*) g_slice_alloc (DIRENT_ALLOC_SIZE);
d = g_slice_new (struct dirent);
/* NOTE: simply memcpy'ing sizeof(struct dirent) bytes will
* give memory errors. */
return (struct dirent*) memcpy (d, entry, entry->d_reclen);
} }
static void static void
dirent_destroy (struct dirent *entry) dirent_destroy (struct dirent *entry)
{ {
g_slice_free (struct dirent, entry); g_slice_free1 (DIRENT_ALLOC_SIZE, entry);
} }
#ifdef HAVE_STRUCT_DIRENT_D_INO #ifdef HAVE_STRUCT_DIRENT_D_INO
@ -464,11 +471,28 @@ process_dir_entries (DIR *dir, const char* path, const char* mdir,
{ {
MuError result; MuError result;
GSList *lst, *c; GSList *lst, *c;
struct dirent *entry;
lst = NULL; lst = NULL;
while ((entry = readdir (dir))) for (;;) {
lst = g_slist_prepend (lst, dirent_copy(entry)); int rv;
struct dirent *entry, *res;
entry = dirent_new ();
rv = readdir_r (dir, entry, &res);
if (rv == 0) {
if (res)
lst = g_slist_prepend (lst, entry);
else {
dirent_destroy (entry);
break; /* last direntry reached */
}
} else {
dirent_destroy (entry);
g_warning ("error scanning dir: %s",
strerror(rv));
return MU_ERROR_FILE;
}
}
/* we sort by inode; this makes things much faster on /* we sort by inode; this makes things much faster on
* extfs2,3 */ * extfs2,3 */
@ -476,7 +500,8 @@ process_dir_entries (DIR *dir, const char* path, const char* mdir,
c = lst = g_slist_sort (lst, (GCompareFunc)dirent_cmp); c = lst = g_slist_sort (lst, (GCompareFunc)dirent_cmp);
#endif /*HAVE_STRUCT_DIRENT_D_INO*/ #endif /*HAVE_STRUCT_DIRENT_D_INO*/
for (c = lst, result = MU_OK; c && result == MU_OK; c = g_slist_next(c)) { for (c = lst, result = MU_OK; c && result == MU_OK;
c = g_slist_next(c)) {
result = process_dir_entry (path, mdir, result = process_dir_entry (path, mdir,
(struct dirent*)c->data, (struct dirent*)c->data,
msg_cb, dir_cb, data); msg_cb, dir_cb, data);
@ -718,7 +743,8 @@ mu_maildir_get_maildir_from_path (const char* path)
/* determine the maildir */ /* determine the maildir */
mdir = g_path_get_dirname (path); mdir = g_path_get_dirname (path);
if (!g_str_has_suffix (mdir, "cur") && !g_str_has_suffix (mdir, "new")) { if (!g_str_has_suffix (mdir, "cur") &&
!g_str_has_suffix (mdir, "new")) {
g_warning ("%s: not a valid maildir path: %s", g_warning ("%s: not a valid maildir path: %s",
__FUNCTION__, path); __FUNCTION__, path);
g_free (mdir); g_free (mdir);