* 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
1 changed files with 53 additions and 27 deletions

View File

@ -55,10 +55,11 @@
* and return it in the d_type parameter
*/
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
#define GET_DTYPE(DE,FP) \
((DE)->d_type == DT_UNKNOWN ? mu_util_get_dtype_with_lstat((FP)) : (DE)->d_type)
#define GET_DTYPE(DE,FP) \
((DE)->d_type == DT_UNKNOWN ? mu_util_get_dtype_with_lstat((FP)) : \
(DE)->d_type)
#else
#define GET_DTYPE(DE,FP) \
#define GET_DTYPE(DE,FP) \
mu_util_get_dtype_with_lstat((FP))
#endif /*HAVE_STRUCT_DIRENT_D_TYPE*/
@ -341,16 +342,23 @@ is_dotdir_to_ignore (const char* dir)
static gboolean
ignore_dir_entry (struct dirent *entry, unsigned char d_type)
{
/* if it's not a dir and not a file, ignore it.
* 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;
if (G_LIKELY(d_type == DT_REG)) {
/* ignore '.' and '..' dirs, as well as .notmuch and
* .nnmaildir */
/* ignore dovecot metadata */
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: {
char *my_mdir;
MuError rv;
/* my_mdir is the search maildir (the dir starting with the top-level
* maildir as /, and without the /tmp, /cur, /new
/* my_mdir is the search maildir (the dir starting
* with the top-level maildir as /, and without the
* /tmp, /cur, /new
*/
my_mdir = get_mdir_for_path (mdir, entry->d_name);
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*
dirent_copy (struct dirent *entry)
dirent_new (void)
{
struct dirent *d;
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);
return (struct dirent*) g_slice_alloc (DIRENT_ALLOC_SIZE);
}
static void
dirent_destroy (struct dirent *entry)
{
g_slice_free (struct dirent, entry);
g_slice_free1 (DIRENT_ALLOC_SIZE, entry);
}
#ifdef HAVE_STRUCT_DIRENT_D_INO
@ -464,11 +471,28 @@ process_dir_entries (DIR *dir, const char* path, const char* mdir,
{
MuError result;
GSList *lst, *c;
struct dirent *entry;
lst = NULL;
while ((entry = readdir (dir)))
lst = g_slist_prepend (lst, dirent_copy(entry));
for (;;) {
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
* 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);
#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,
(struct dirent*)c->data,
msg_cb, dir_cb, data);
@ -718,7 +743,8 @@ mu_maildir_get_maildir_from_path (const char* path)
/* determine the maildir */
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",
__FUNCTION__, path);
g_free (mdir);