Mercurial > dovecot > core-2.2
changeset 4351:61cc7e40bec6 HEAD
Add ",S=size" to maildir filenames when quota plugin is loaded with
Maildir++ backend.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 16 Jun 2006 12:40:40 +0300 |
parents | a916c98dc910 |
children | d57c83c64b20 |
files | src/lib-storage/index/maildir/maildir-copy.c src/lib-storage/index/maildir/maildir-mail.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-util.c src/plugins/quota/Makefile.am src/plugins/quota/quota-maildir.c |
diffstat | 7 files changed, 160 insertions(+), 80 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/maildir/maildir-copy.c Fri Jun 16 12:33:10 2006 +0300 +++ b/src/lib-storage/index/maildir/maildir-copy.c Fri Jun 16 12:40:40 2006 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "array.h" #include "ioloop.h" +#include "str.h" #include "maildir-storage.h" #include "maildir-uidlist.h" #include "maildir-keywords.h" @@ -11,18 +12,59 @@ #include <stdlib.h> #include <unistd.h> +#include <sys/stat.h> struct hardlink_ctx { - const char *dest_path; - bool success; + string_t *dest_path; + const char *dest_fname; + unsigned int base_end_pos; + + unsigned int size_set:1; + unsigned int success:1; }; +static int do_save_mail_size(struct maildir_mailbox *mbox, const char *path, + struct hardlink_ctx *ctx) +{ + const char *fname, *str; + struct stat st; + uoff_t size; + + fname = strrchr(path, '/'); + fname = fname != NULL ? fname + 1 : path; + + if (!maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE, + &size)) { + if (stat(path, &st) < 0) { + if (errno == ENOENT) + return 0; + mail_storage_set_critical(STORAGE(mbox->storage), + "stat(%s) failed: %m", path); + return -1; + } + size = st.st_size; + } + + str = t_strdup_printf(",S=%"PRIuUOFF_T, size); + str_insert(ctx->dest_path, ctx->base_end_pos, str); + + ctx->dest_fname = strrchr(str_c(ctx->dest_path), '/') + 1; + ctx->size_set = TRUE; + return 1; +} + static int do_hardlink(struct maildir_mailbox *mbox, const char *path, void *context) { struct hardlink_ctx *ctx = context; + int ret; - if (link(path, ctx->dest_path) < 0) { + if (mbox->storage->save_size_in_filename && !ctx->size_set) { + if ((ret = do_save_mail_size(mbox, path, ctx)) <= 0) + return ret; + } + + if (link(path, str_c(ctx->dest_path)) < 0) { if (errno == ENOENT) return 0; @@ -36,7 +78,7 @@ mail_storage_set_critical(STORAGE(mbox->storage), "link(%s, %s) failed: %m", - path, ctx->dest_path); + path, str_c(ctx->dest_path)); return -1; } @@ -55,7 +97,6 @@ (struct maildir_mailbox *)mail->box; struct maildir_save_context *ctx; struct hardlink_ctx do_ctx; - const char *dest_fname; uint32_t seq; i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0); @@ -70,31 +111,33 @@ flags |= MAIL_RECENT; memset(&do_ctx, 0, sizeof(do_ctx)); + do_ctx.dest_path = str_new(default_pool, 512); /* the generated filename is _always_ unique, so we don't bother trying to check if it already exists */ - dest_fname = maildir_generate_tmp_filename(&ioloop_timeval); + do_ctx.dest_fname = maildir_generate_tmp_filename(&ioloop_timeval); if (keywords == NULL || keywords->count == 0) { /* no keywords, hardlink directly to destination */ if (flags == MAIL_RECENT) { - do_ctx.dest_path = - t_strconcat(dest_mbox->path, "/new/", - dest_fname, NULL); + str_printfa(do_ctx.dest_path, "%s/new/%s", + dest_mbox->path, do_ctx.dest_fname); + do_ctx.base_end_pos = str_len(do_ctx.dest_path); } else { - const char *fname; - - fname = maildir_filename_set_flags(NULL, dest_fname, - flags, NULL); - - do_ctx.dest_path = - t_strconcat(dest_mbox->path, "/cur/", - fname, NULL); + str_printfa(do_ctx.dest_path, "%s/cur/", + dest_mbox->path); + do_ctx.base_end_pos = str_len(do_ctx.dest_path) + + strlen(do_ctx.dest_fname); + str_append(do_ctx.dest_path, + maildir_filename_set_flags(NULL, + do_ctx.dest_fname, + flags, NULL)); } } else { /* keywords, hardlink to tmp/ with basename and later when we have uidlist locked, move it to new/cur. */ - do_ctx.dest_path = - t_strconcat(dest_mbox->path, "/tmp/", dest_fname, NULL); + str_printfa(do_ctx.dest_path, "%s/tmp/%s", + dest_mbox->path, do_ctx.dest_fname); + do_ctx.base_end_pos = str_len(do_ctx.dest_path); } if (maildir_file_do(src_mbox, mail->uid, do_hardlink, &do_ctx) < 0) return -1; @@ -106,12 +149,12 @@ if (keywords == NULL || keywords->count == 0) { /* hardlinked to destination, set hardlinked-flag */ - seq = maildir_save_add(t, dest_fname, + seq = maildir_save_add(t, do_ctx.dest_fname, flags | MAILDIR_SAVE_FLAG_HARDLINK, NULL, dest_mail); } else { /* hardlinked to tmp/, treat as normal copied mail */ - seq = maildir_save_add(t, dest_fname, flags, keywords, + seq = maildir_save_add(t, do_ctx.dest_fname, flags, keywords, dest_mail); } return 1;
--- a/src/lib-storage/index/maildir/maildir-mail.c Fri Jun 16 12:33:10 2006 +0300 +++ b/src/lib-storage/index/maildir/maildir-mail.c Fri Jun 16 12:40:40 2006 +0300 @@ -121,7 +121,7 @@ struct index_mail *mail = (struct index_mail *)_mail; struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox; struct index_mail_data *data = &mail->data; - const char *fname, *p; + const char *fname; uoff_t virtual_size; enum maildir_uidlist_rec_flag flags; @@ -145,22 +145,11 @@ } /* size can be included in filename */ - p = strstr(fname, MAILDIR_EXTRA_SEP_S MAILDIR_EXTRA_VIRTUAL_SIZE "="); - if (p != NULL) { - p += 3; - virtual_size = 0; - while (*p >= '0' && *p <= '9') { - virtual_size = virtual_size * 10 + (*p - '0'); - p++; - } - - if (*p == MAILDIR_INFO_SEP || *p == MAILDIR_EXTRA_SEP || - *p == '\0') { - index_mail_cache_add(mail, MAIL_CACHE_VIRTUAL_FULL_SIZE, - &virtual_size, - sizeof(virtual_size)); - return virtual_size; - } + if (maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE, + &virtual_size)) { + index_mail_cache_add(mail, MAIL_CACHE_VIRTUAL_FULL_SIZE, + &virtual_size, sizeof(virtual_size)); + return virtual_size; } return index_mail_get_virtual_size(_mail); @@ -195,7 +184,7 @@ struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->ibox; struct index_mail_data *data = &mail->data; struct stat st; - const char *fname, *p; + const char *fname; uoff_t size; enum maildir_uidlist_rec_flag flags; @@ -214,26 +203,13 @@ } /* size can be included in filename */ - p = strstr(fname, MAILDIR_EXTRA_SEP_S MAILDIR_EXTRA_FILE_SIZE "="); - if (p != NULL) { - p += 3; - size = 0; - while (*p >= '0' && *p <= '9') { - size = size * 10 + (*p - '0'); - p++; - } - - if (*p != MAILDIR_INFO_SEP && - *p != MAILDIR_EXTRA_SEP && *p != '\0') - size = (uoff_t)-1; - } - - if (size == (uoff_t)-1) { + if (!maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE, &size)) { if (_mail->uid != 0) { if (maildir_file_do(mbox, _mail->uid, do_stat, &st) <= 0) return (uoff_t)-1; } else { + /* saved mail which hasn't been committed yet */ if (do_stat(mbox, fname, &st) <= 0) return (uoff_t)-1; }
--- a/src/lib-storage/index/maildir/maildir-save.c Fri Jun 16 12:33:10 2006 +0300 +++ b/src/lib-storage/index/maildir/maildir-save.c Fri Jun 16 12:40:40 2006 +0300 @@ -24,6 +24,7 @@ struct maildir_filename *next; const char *basename; + uoff_t size; enum mail_flags flags; unsigned int keywords_count; /* unsigned int keywords[]; */ @@ -58,7 +59,8 @@ }; static int maildir_file_move(struct maildir_save_context *ctx, - const char *basename, const char *dest) + const char *tmpname, const char *destname, + bool newdir) { const char *tmp_path, *new_path; int ret; @@ -69,10 +71,10 @@ new/ directory can't have flags. alternative would be to write it in new/ and set the flags dirty in index file, but in that case external MUAs would see wrong flags. */ - tmp_path = t_strconcat(ctx->tmpdir, "/", basename, NULL); - new_path = dest == NULL ? - t_strconcat(ctx->newdir, "/", basename, NULL) : - t_strconcat(ctx->curdir, "/", dest, NULL); + tmp_path = t_strconcat(ctx->tmpdir, "/", tmpname, NULL); + new_path = newdir ? + t_strconcat(ctx->newdir, "/", destname, NULL) : + t_strconcat(ctx->curdir, "/", destname, NULL); if (link(tmp_path, new_path) == 0) ret = 0; @@ -148,6 +150,7 @@ keywords->count)); mf->basename = p_strdup(ctx->pool, base_fname); mf->flags = flags; + mf->size = (uoff_t)-1; if (*ctx->files_tail != NULL) (*ctx->files_tail)->next = mf; @@ -204,24 +207,37 @@ return ctx->seq; } -static const char * +static bool maildir_get_updated_filename(struct maildir_save_context *ctx, - struct maildir_filename *mf) + struct maildir_filename *mf, + const char **fname_r) { + const char *basename = mf->basename; + + if (ctx->mbox->storage->save_size_in_filename && + mf->size != (uoff_t)-1) { + basename = t_strdup_printf("%s,S=%"PRIuUOFF_T, + basename, mf->size); + } + if (mf->keywords_count == 0) { - if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) - return NULL; - return maildir_filename_set_flags(NULL, mf->basename, - mf->flags & MAIL_FLAGS_MASK, - NULL); + if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) { + *fname_r = basename; + return TRUE; + } + + *fname_r = maildir_filename_set_flags(NULL, basename, + mf->flags & MAIL_FLAGS_MASK, NULL); + return FALSE; } buffer_update_const_data(ctx->keywords_buffer, mf + 1, mf->keywords_count * sizeof(unsigned int)); - return maildir_filename_set_flags( + *fname_r = maildir_filename_set_flags( maildir_sync_get_keywords_sync_ctx(ctx->sync_ctx), - mf->basename, mf->flags & MAIL_FLAGS_MASK, + basename, mf->flags & MAIL_FLAGS_MASK, &ctx->keywords_array); + return FALSE; } static const char *maildir_mf_get_path(struct maildir_save_context *ctx, @@ -235,8 +251,7 @@ } /* already moved to new/ or cur/ */ - fname = maildir_get_updated_filename(ctx, mf); - if (fname == NULL) + if (maildir_get_updated_filename(ctx, mf, &fname)) return t_strdup_printf("%s/%s", ctx->newdir, mf->basename); else return t_strdup_printf("%s/%s", ctx->curdir, fname); @@ -359,6 +374,9 @@ return -1; } + /* remember the size in case we want to add it to filename */ + ctx->files->size = ctx->output->offset; + t_push(); path = t_strconcat(ctx->tmpdir, "/", ctx->files->basename, NULL); @@ -447,7 +465,8 @@ struct maildir_filename *mf; uint32_t first_uid, last_uid; enum maildir_uidlist_rec_flag flags; - const char *dest, *fname; + const char *dest; + bool newdir; int ret; i_assert(ctx->output == NULL); @@ -488,18 +507,19 @@ ctx->moving = TRUE; for (mf = ctx->files; mf != NULL && ret == 0; mf = mf->next) { t_push(); - dest = maildir_get_updated_filename(ctx, mf); - fname = dest != NULL ? dest : mf->basename; + newdir = maildir_get_updated_filename(ctx, mf, &dest); /* if hardlink-flag is set, the file is already in destination. if the hardlinked mail contained keywords, it was linked into tmp/ and it doesn't have the hardlink-flag set, so it's treated as any other saved mail. */ - if ((mf->flags & MAILDIR_SAVE_FLAG_HARDLINK) == 0) - ret = maildir_file_move(ctx, mf->basename, dest); + if ((mf->flags & MAILDIR_SAVE_FLAG_HARDLINK) == 0) { + ret = maildir_file_move(ctx, mf->basename, + dest, newdir); + } if (ret == 0) { ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx, - fname, flags); + dest, flags); i_assert(ret != 0); ret = ret < 0 ? -1 : 0; }
--- a/src/lib-storage/index/maildir/maildir-storage.h Fri Jun 16 12:33:10 2006 +0300 +++ b/src/lib-storage/index/maildir/maildir-storage.h Fri Jun 16 12:40:40 2006 +0300 @@ -27,10 +27,10 @@ #define MAILDIR_MAX_KEYWORDS (MAILDIR_KEYWORD_LAST - MAILDIR_KEYWORD_FIRST + 1) /* Maildir++ extension: include file size in the filename to avoid stat() */ -#define MAILDIR_EXTRA_FILE_SIZE "S" +#define MAILDIR_EXTRA_FILE_SIZE 'S' /* Something (can't remember what anymore) could use 'W' in filename to avoid calculating file's virtual size (added missing CRs). */ -#define MAILDIR_EXTRA_VIRTUAL_SIZE "W" +#define MAILDIR_EXTRA_VIRTUAL_SIZE 'W' #define MAILDIR_SAVE_FLAG_HARDLINK 0x10000000 #define MAILDIR_SAVE_FLAG_DELETED 0x20000000 @@ -53,6 +53,7 @@ const char *control_dir; unsigned int copy_with_hardlinks:1; + unsigned int save_size_in_filename:1; }; struct maildir_mailbox { @@ -89,6 +90,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); +bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r); struct mailbox_list_context * maildir_mailbox_list_init(struct mail_storage *storage,
--- a/src/lib-storage/index/maildir/maildir-util.c Fri Jun 16 12:33:10 2006 +0300 +++ b/src/lib-storage/index/maildir/maildir-util.c Fri Jun 16 12:40:40 2006 +0300 @@ -134,6 +134,34 @@ return fd; } +bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r) +{ + uoff_t size = 0; + + for (; *fname != '\0'; fname++) { + if (*fname == ',' && fname[1] == type && fname[2] == '=') { + fname += 3; + break; + } + } + + if (*fname == '\0') + return FALSE; + + while (*fname >= '0' && *fname <= '9') { + size = size * 10 + (*fname - '0'); + fname++; + } + + if (*fname != MAILDIR_INFO_SEP && + *fname != MAILDIR_EXTRA_SEP && + *fname != '\0') + return FALSE; + + *size_r = size; + return TRUE; +} + /* a char* hash function from ASU -- from glib */ unsigned int maildir_hash(const void *p) {
--- a/src/plugins/quota/Makefile.am Fri Jun 16 12:33:10 2006 +0300 +++ b/src/plugins/quota/Makefile.am Fri Jun 16 12:40:40 2006 +0300 @@ -1,8 +1,11 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib-dict \ + -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-mail \ - -I$(top_srcdir)/src/lib-storage + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-storage/index \ + -I$(top_srcdir)/src/lib-storage/index/maildir lib01_quota_plugin_la_LDFLAGS = -module -avoid-version
--- a/src/plugins/quota/quota-maildir.c Fri Jun 16 12:33:10 2006 +0300 +++ b/src/plugins/quota/quota-maildir.c Fri Jun 16 12:40:40 2006 +0300 @@ -8,6 +8,7 @@ #include "read-full.h" #include "write-full.h" #include "str.h" +#include "maildir-storage.h" #include "quota-private.h" #include <stdio.h> @@ -552,8 +553,15 @@ static bool maildir_quota_add_storage(struct quota_root *root __attr_unused__, - struct mail_storage *storage __attr_unused__) + struct mail_storage *_storage) { + if (strcmp(_storage->name, "maildir") == 0) { + struct maildir_storage *storage = + (struct maildir_storage *)_storage; + + /* For newly generated filenames add ,S=size. */ + storage->save_size_in_filename = TRUE; + } return TRUE; }