Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/maildir/maildir-util.c @ 6885:a22b1a72ea89 HEAD
Code cleanup
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 01 Dec 2007 10:31:02 +0200 |
parents | 186b164a9579 |
children | 82420ed23379 |
line wrap: on
line source
/* Copyright (c) 2004-2007 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "ioloop.h" #include "str.h" #include "mkdir-parents.h" #include "maildir-storage.h" #include "maildir-uidlist.h" #include "maildir-sync.h" #include <unistd.h> #include <dirent.h> #include <fcntl.h> #include <utime.h> #include <sys/stat.h> #define MAILDIR_RESYNC_RETRY_COUNT 10 static int maildir_file_do_try(struct maildir_mailbox *mbox, uint32_t uid, maildir_file_do_func *callback, void *context) { const char *fname, *path; enum maildir_uidlist_rec_flag flags; int ret; fname = maildir_uidlist_lookup(mbox->uidlist, uid, &flags); if (fname == NULL) return -2; /* expunged */ t_push(); if ((flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) { /* probably in new/ dir */ path = t_strconcat(mbox->path, "/new/", fname, NULL); ret = callback(mbox, path, context); if (ret != 0) { t_pop(); return ret; } } path = t_strconcat(mbox->path, "/cur/", fname, NULL); ret = callback(mbox, path, context); t_pop(); return ret; } static int do_racecheck(struct maildir_mailbox *mbox, const char *path, void *context ATTR_UNUSED) { struct stat st; if (lstat(path, &st) == 0 && (st.st_mode & S_IFLNK) != 0) { /* most likely a symlink pointing to a non-existing file */ mail_storage_set_critical(&mbox->storage->storage, "Maildir: Symlink destination doesn't exist: %s", path); return -2; } else { mail_storage_set_critical(&mbox->storage->storage, "maildir_file_do(%s): Filename keeps changing", path); return -1; } } #undef maildir_file_do int maildir_file_do(struct maildir_mailbox *mbox, uint32_t uid, maildir_file_do_func *callback, void *context) { int i, ret; ret = maildir_file_do_try(mbox, uid, callback, context); for (i = 0; i < MAILDIR_RESYNC_RETRY_COUNT && ret == 0; i++) { /* file is either renamed or deleted. sync the maildir and see which one. if file appears to be renamed constantly, don't try to open it more than 10 times. */ if (maildir_storage_sync_force(mbox) < 0) return -1; ret = maildir_file_do_try(mbox, uid, callback, context); } if (i == MAILDIR_RESYNC_RETRY_COUNT) ret = maildir_file_do_try(mbox, uid, do_racecheck, context); return ret == -2 ? 0 : ret; } void maildir_tmp_cleanup(struct mail_storage *storage, const char *dir) { DIR *dirp; struct dirent *d; struct stat st; string_t *path; unsigned int dir_len; dirp = opendir(dir); if (dirp == NULL) { if (errno != ENOENT) { mail_storage_set_critical(storage, "opendir(%s) failed: %m", dir); } return; } t_push(); path = t_str_new(256); str_printfa(path, "%s/", dir); dir_len = str_len(path); while ((d = readdir(dirp)) != NULL) { if (d->d_name[0] == '.' && (d->d_name[1] == '\0' || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) { /* skip . and .. */ continue; } str_truncate(path, dir_len); str_append(path, d->d_name); if (stat(str_c(path), &st) < 0) { if (errno != ENOENT) { mail_storage_set_critical(storage, "stat(%s) failed: %m", str_c(path)); } } else if (st.st_ctime <= ioloop_time - MAILDIR_TMP_DELETE_SECS) { if (unlink(str_c(path)) < 0 && errno != ENOENT) { mail_storage_set_critical(storage, "unlink(%s) failed: %m", str_c(path)); } } } t_pop(); #ifdef HAVE_DIRFD if (fstat(dirfd(dirp), &st) < 0) { mail_storage_set_critical(storage, "fstat(%s) failed: %m", dir); } #else if (stat(dir, &st) < 0) { mail_storage_set_critical(storage, "stat(%s) failed: %m", dir); } #endif else if (st.st_atime < ioloop_time) { /* mounted with noatime. update it ourself. */ if (utime(dir, NULL) < 0 && errno != ENOENT) { mail_storage_set_critical(storage, "utime(%s) failed: %m", dir); } } if (closedir(dirp) < 0) { mail_storage_set_critical(storage, "closedir(%s) failed: %m", dir); } } static int maildir_create_subdirs(struct maildir_mailbox *mbox) { static const char *subdirs[] = { "cur", "new", "tmp" }; const char *dirs[N_ELEMENTS(subdirs) + 2]; struct mailbox *box = &mbox->ibox.box; struct stat st; const char *path; unsigned int i; t_push(); /* @UNSAFE: get a list of directories we want to create */ for (i = 0; i < N_ELEMENTS(subdirs); i++) dirs[i] = t_strconcat(mbox->path, "/", subdirs[i], NULL); dirs[i++] = mail_storage_get_mailbox_control_dir(box->storage, box->name); dirs[i++] = mail_storage_get_mailbox_index_dir(box->storage, box->name); i_assert(i == N_ELEMENTS(dirs)); for (i = 0; i < N_ELEMENTS(dirs); i++) { path = dirs[i]; if (path == NULL || stat(path, &st) == 0) continue; if (errno != ENOENT) { mail_storage_set_critical(box->storage, "stat(%s) failed: %m", path); break; } if (mkdir_parents(path, box->dir_create_mode) < 0 && errno != EEXIST) { if (errno == ENOENT) { /* mailbox was being deleted just now */ mailbox_set_deleted(box); break; } mail_storage_set_critical(box->storage, "mkdir(%s) failed: %m", path); break; } } t_pop(); return i == N_ELEMENTS(dirs) ? 0 : -1; } bool maildir_set_deleted(struct maildir_mailbox *mbox) { struct mailbox *box = &mbox->ibox.box; struct stat st; if (stat(mbox->path, &st) < 0) { if (errno == ENOENT) mailbox_set_deleted(box); else { mail_storage_set_critical(box->storage, "stat(%s) failed: %m", mbox->path); } return TRUE; } /* maildir itself exists. create all of its subdirectories in case they got lost. */ return maildir_create_subdirs(mbox) < 0 ? TRUE : FALSE; }