Mercurial > dovecot > core-2.2
view src/lib-storage/index/maildir/maildir-save.c @ 1915:79790750c349 HEAD
importing new index code. mbox still broken.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 27 Apr 2004 23:25:52 +0300 |
parents | ffd430238c32 |
children | 4dec6a3d79fd |
line wrap: on
line source
/* Copyright (C) 2002-2004 Timo Sirainen */ #include "lib.h" #include "ioloop.h" #include "ostream.h" #include "maildir-storage.h" #include "mail-save.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <utime.h> #include <sys/stat.h> struct maildir_filename { struct maildir_filename *next; const char *src, *dest; }; struct maildir_save_context { pool_t pool; struct index_mailbox *ibox; const char *tmpdir, *newdir; struct maildir_filename *files; }; static const char * maildir_read_into_tmp(struct index_mailbox *ibox, const char *dir, struct istream *input) { const char *path, *fname; struct ostream *output; int fd; fd = maildir_create_tmp(ibox, dir, ibox->mail_create_mode, &path); if (fd == -1) return NULL; fname = strrchr(path, '/'); i_assert(fname != NULL); fname++; output = o_stream_create_file(fd, pool_datastack_create(), 4096, FALSE); o_stream_set_blocking(output, 60000, NULL, NULL); if (mail_storage_save(ibox->box.storage, path, input, output, getenv("MAIL_SAVE_CRLF") != NULL, NULL, NULL) < 0) fname = NULL; o_stream_unref(output); /* FIXME: when saving multiple messages, we could get better performance if we left the fd open and fsync()ed it later */ if (fsync(fd) < 0) { mail_storage_set_critical(ibox->box.storage, "fsync() failed for %s: %m", path); fname = NULL; } if (close(fd) < 0) { mail_storage_set_critical(ibox->box.storage, "close() failed for %s: %m", path); fname = NULL; } if (fname == NULL) (void)unlink(path); return fname; } static int maildir_file_move(struct maildir_save_context *ctx, const char *src, const char *dest) { const char *tmp_path, *new_path; int ret; t_push(); tmp_path = t_strconcat(ctx->tmpdir, "/", src, NULL); new_path = t_strconcat(ctx->newdir, "/", dest, NULL); if (link(tmp_path, new_path) == 0) ret = 0; else { ret = -1; if (ENOSPACE(errno)) { mail_storage_set_error(ctx->ibox->box.storage, "Not enough disk space"); } else { mail_storage_set_critical(ctx->ibox->box.storage, "link(%s, %s) failed: %m", tmp_path, new_path); } } if (unlink(tmp_path) < 0 && errno != ENOENT) { mail_storage_set_critical(ctx->ibox->box.storage, "unlink(%s) failed: %m", tmp_path); } t_pop(); return ret; } static struct maildir_save_context * mailbox_save_init(struct index_mailbox *ibox) { struct maildir_save_context *ctx; pool_t pool; pool = pool_alloconly_create("maildir_save_context", 4096); ctx = p_new(pool, struct maildir_save_context, 1); ctx->pool = pool; ctx->ibox = ibox; ctx->tmpdir = p_strconcat(pool, ibox->path, "/tmp", NULL); ctx->newdir = p_strconcat(pool, ibox->path, "/new", NULL); return ctx; } int maildir_save(struct mailbox_transaction_context *_t, const struct mail_full_flags *flags, time_t received_date, int timezone_offset __attr_unused__, const char *from_envelope __attr_unused__, struct istream *data) { struct maildir_transaction_context *t = (struct maildir_transaction_context *)_t; struct maildir_save_context *ctx; struct index_mailbox *ibox = t->ictx.ibox; struct maildir_filename *mf; enum mail_flags mail_flags; struct utimbuf buf; const char *fname, *dest_fname, *tmp_path; if (t->save_ctx == NULL) t->save_ctx = mailbox_save_init(ibox); ctx = t->save_ctx; mail_flags = flags->flags; /*FIXME:if (!index_mailbox_fix_custom_flags(ibox, &mail_flags, flags->custom_flags, flags->custom_flags_count)) return FALSE;*/ t_push(); /* create the file into tmp/ directory */ fname = maildir_read_into_tmp(ibox, ctx->tmpdir, data); if (fname == NULL) { t_pop(); return -1; } tmp_path = t_strconcat(ctx->tmpdir, "/", fname, NULL); if (received_date != (time_t)-1) { /* set the received_date by modifying mtime */ buf.actime = ioloop_time; buf.modtime = received_date; if (utime(tmp_path, &buf) < 0) { mail_storage_set_critical(ibox->box.storage, "utime(%s) failed: %m", tmp_path); t_pop(); return -1; } } /* now, we want to be able to rollback the whole append session, so we'll just store the name of this temp file and move it later into new/ */ dest_fname = mail_flags == 0 ? fname : maildir_filename_set_flags(fname, mail_flags, NULL); mf = p_new(ctx->pool, struct maildir_filename, 1); mf->next = ctx->files; mf->src = p_strdup(ctx->pool, fname); mf->dest = p_strdup(ctx->pool, dest_fname); ctx->files = mf; t_pop(); return 0; } int maildir_save_commit(struct maildir_save_context *ctx) { struct maildir_filename *mf, *mf2; const char *path; int ret = 0; /* move them into new/ */ for (mf = ctx->files; mf != NULL; mf = mf->next) { if (maildir_file_move(ctx, mf->src, mf->dest) < 0) { ret = -1; break; } } if (ret < 0) { /* failed, try to unlink the mails already moved */ for (mf2 = ctx->files; mf2 != mf; mf2 = mf2->next) { t_push(); path = t_strconcat(ctx->newdir, "/", mf2->dest, NULL); (void)unlink(path); t_pop(); } } pool_unref(ctx->pool); return ret; } void maildir_save_rollback(struct maildir_save_context *ctx) { struct maildir_filename *mf; const char *path; /* clean up the temp files */ for (mf = ctx->files; mf != NULL; mf = mf->next) { t_push(); path = t_strconcat(ctx->tmpdir, "/", mf->dest, NULL); (void)unlink(path); t_pop(); } pool_unref(ctx->pool); }