void dbox_save_end(struct dbox_save_context *ctx) { struct mail_save_data *mdata = &ctx->ctx.data; struct ostream *dbox_output = ctx->dbox_output; if (mdata->attach != NULL && !ctx->failed) { if (index_attachment_save_finish(&ctx->ctx) < 0) ctx->failed = TRUE; } if (o_stream_nfinish(mdata->output) < 0) { mail_storage_set_critical(ctx->ctx.transaction->box->storage, "write(%s) failed: %m", o_stream_get_name(mdata->output)); ctx->failed = TRUE; } if (mdata->output != dbox_output) { if (mdata->output != NULL) { /* e.g. zlib plugin had changed this */ o_stream_ref(dbox_output); o_stream_destroy(&mdata->output); mdata->output = dbox_output; } else { i_assert(ctx->failed); } } index_mail_cache_parse_deinit(ctx->ctx.dest_mail, ctx->ctx.data.received_date, !ctx->failed); }
static int maildir_save_finish_real(struct mail_save_context *_ctx) { struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx; struct mail_storage *storage = &ctx->mbox->storage->storage; const char *path; off_t real_size; uoff_t size; int output_errno; ctx->last_save_finished = TRUE; if (ctx->failed && ctx->fd == -1) { /* tmp file creation failed */ return -1; } path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->tmp_name, NULL); if (!ctx->failed && o_stream_nfinish(_ctx->data.output) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "write(%s) failed: %m", path); } ctx->failed = TRUE; } if (_ctx->data.save_date != (time_t)-1) { /* we can't change ctime, but we can add the date to cache */ struct index_mail *mail = (struct index_mail *)_ctx->dest_mail; uint32_t t = _ctx->data.save_date; index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t)); } if (maildir_save_finish_received_date(ctx, path) < 0) ctx->failed = TRUE; if (ctx->cur_dest_mail != NULL) { index_mail_cache_parse_deinit(ctx->cur_dest_mail, ctx->ctx.data.received_date, !ctx->failed); } i_stream_unref(&ctx->input); /* remember the size in case we want to add it to filename */ ctx->file_last->size = _ctx->data.output->offset; if (ctx->cur_dest_mail == NULL || mail_get_virtual_size(ctx->cur_dest_mail, &ctx->file_last->vsize) < 0) ctx->file_last->vsize = (uoff_t)-1; output_errno = _ctx->data.output->last_failed_errno; o_stream_destroy(&_ctx->data.output); if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER && !ctx->failed) { if (fsync(ctx->fd) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "fsync(%s) failed: %m", path); } ctx->failed = TRUE; } } real_size = lseek(ctx->fd, 0, SEEK_END); if (real_size == (off_t)-1) { mail_storage_set_critical(storage, "lseek(%s) failed: %m", path); } else if (real_size != (off_t)ctx->file_last->size && (!maildir_filename_get_size(ctx->file_last->dest_basename, MAILDIR_EXTRA_FILE_SIZE, &size) || size != ctx->file_last->size)) { /* e.g. zlib plugin was used. the "physical size" must be in the maildir filename, since stat() will return wrong size */ ctx->file_last->preserve_filename = FALSE; /* preserve the GUID if needed */ if (ctx->file_last->guid == NULL) ctx->file_last->guid = ctx->file_last->dest_basename; /* reset the base name as well, just in case there's a ,W=vsize */ ctx->file_last->dest_basename = ctx->file_last->tmp_name; } if (close(ctx->fd) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "close(%s) failed: %m", path); } ctx->failed = TRUE; } ctx->fd = -1; if (ctx->failed) { /* delete the tmp file */ i_unlink_if_exists(path); errno = output_errno; if (ENOQUOTA(errno)) { mail_storage_set_error(storage, MAIL_ERROR_NOQUOTA, MAIL_ERRSTR_NO_QUOTA); } else if (errno != 0) { mail_storage_set_critical(storage, "write(%s) failed: %m", path); } maildir_save_remove_last_filename(ctx); return -1; } ctx->file_last = NULL; return 0; }