# HG changeset patch # User Timo Sirainen # Date 1168966746 -7200 # Node ID 06b281c1f5434fc0e09396cf0fd8ef0cbeb33573 # Parent 5ea657b6d83c2d7c7aa1b0042fc79e0ec7667547 When opening maildir, check if tmp/'s atime is over 8h old. If it is, delete old files in it. However if atime - ctime > 36h, it means there's nothing to be deleted so the scanning isn't done then. We update atime if filesystem is mounted with noatime. diff -r 5ea657b6d83c -r 06b281c1f543 configure.in --- a/configure.in Tue Jan 16 17:07:43 2007 +0200 +++ b/configure.in Tue Jan 16 18:59:06 2007 +0200 @@ -411,7 +411,7 @@ strcasecmp stricmp vsnprintf vsyslog writev pread \ setrlimit setproctitle seteuid setreuid setegid setresgid \ strtoull strtouq setpriority quotactl getmntent kqueue kevent \ - getrusage backtrace_symbols walkcontext) + getrusage backtrace_symbols walkcontext dirfd) dnl * I/O loop function have_ioloop=no diff -r 5ea657b6d83c -r 06b281c1f543 src/lib-storage/index/maildir/maildir-storage.c --- a/src/lib-storage/index/maildir/maildir-storage.c Tue Jan 16 17:07:43 2007 +0200 +++ b/src/lib-storage/index/maildir/maildir-storage.c Tue Jan 16 18:59:06 2007 +0200 @@ -32,8 +32,6 @@ extern struct mail_storage maildir_storage; extern struct mailbox maildir_mailbox; -static const char *maildirs[] = { "cur", "new", "tmp", NULL }; - static int verify_inbox(struct mail_storage *storage); static const char *strip_tail_slash(const char *path) @@ -257,25 +255,26 @@ struct stat st; if (verify) { - if (lstat(dir, &st) == 0) + if (stat(dir, &st) == 0) return 0; if (errno != ENOENT) { mail_storage_set_critical(storage, - "lstat(%s) failed: %m", dir); + "stat(%s) failed: %m", dir); return -1; } } - if (mkdir_parents(dir, CREATE_MODE) < 0 && - (errno != EEXIST || !verify)) { - if (errno != EEXIST && (!verify || errno != ENOENT)) { + if (mkdir_parents(dir, CREATE_MODE) < 0) { + if (errno == EEXIST) { + if (!verify) + return -1; + } else { mail_storage_set_critical(storage, "mkdir(%s) failed: %m", dir); + return -1; } - return -1; } - return 0; } @@ -283,26 +282,31 @@ static int create_maildir(struct mail_storage *storage, const char *dir, bool verify) { - const char **tmp, *path; + const char *path; + struct stat st; - if (!verify && mkdir_verify(storage, dir, verify) < 0) + if (mkdir_verify(storage, t_strconcat(dir, "/cur", NULL), verify) < 0) + return -1; + if (mkdir_verify(storage, t_strconcat(dir, "/new", NULL), verify) < 0) return -1; - for (tmp = maildirs; *tmp != NULL; tmp++) { - path = t_strconcat(dir, "/", *tmp, NULL); - - if (mkdir_verify(storage, path, verify) < 0) { - if (!verify || errno != ENOENT) - return -1; - - /* small optimization. if we're verifying, we don't - check that the root dir actually exists unless we - fail here. */ - if (mkdir_verify(storage, dir, verify) < 0) - return -1; - if (mkdir_verify(storage, path, verify) < 0) - return -1; + /* if tmp/ directory exists, we need to clean it up once in a while */ + path = t_strconcat(dir, "/tmp", NULL); + if (stat(path, &st) == 0) { + if (st.st_atime > + st.st_ctime + MAILDIR_TMP_DELETE_SECS) { + /* the directory should be empty. we won't do anything + until ctime changes. */ + } else if (st.st_atime < ioloop_time - MAILDIR_TMP_SCAN_SECS) { + /* time to scan */ + (void)maildir_tmp_cleanup(storage, path); } + } else if (errno == ENOENT) { + if (mkdir_verify(storage, path, verify) < 0) + return -1; + } else { + mail_storage_set_critical(storage, "stat(%s) failed: %m", path); + return -1; } return 0; diff -r 5ea657b6d83c -r 06b281c1f543 src/lib-storage/index/maildir/maildir-storage.h --- a/src/lib-storage/index/maildir/maildir-storage.h Tue Jan 16 17:07:43 2007 +0200 +++ b/src/lib-storage/index/maildir/maildir-storage.h Tue Jan 16 18:59:06 2007 +0200 @@ -29,6 +29,11 @@ calculating file's virtual size (added missing CRs). */ #define MAILDIR_EXTRA_VIRTUAL_SIZE 'W' +/* How often to scan tmp/ directory for old files (based on dir's atime) */ +#define MAILDIR_TMP_SCAN_SECS (8*60*60) +/* Delete files having ctime older than this from tmp/. 36h is standard. */ +#define MAILDIR_TMP_DELETE_SECS (36*60*60) + #define MAILDIR_SAVE_FLAG_HARDLINK 0x10000000 #define MAILDIR_SAVE_FLAG_DELETED 0x20000000 @@ -105,6 +110,7 @@ const char *maildir_generate_tmp_filename(const struct timeval *tv); int maildir_create_tmp(struct maildir_mailbox *mbox, const char *dir, mode_t mode, const char **fname_r); +void maildir_tmp_cleanup(struct mail_storage *storage, const char *dir); bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r); void maildir_transaction_created(struct mail_index_transaction *t); diff -r 5ea657b6d83c -r 06b281c1f543 src/lib-storage/index/maildir/maildir-util.c --- a/src/lib-storage/index/maildir/maildir-util.c Tue Jan 16 17:07:43 2007 +0200 +++ b/src/lib-storage/index/maildir/maildir-util.c Tue Jan 16 18:59:06 2007 +0200 @@ -10,7 +10,9 @@ #include "maildir-sync.h" #include +#include #include +#include #include static int maildir_file_do_try(struct maildir_mailbox *mbox, uint32_t uid, @@ -136,6 +138,83 @@ return fd; } +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. */ + struct utimbuf ut; + + ut.actime = ioloop_time; + ut.modtime = st.st_mtime; + + if (utime(dir, &ut) < 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); + } +} + bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r) { uoff_t size = 0;