~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib-storage/index/mbox/mbox-save.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "ioloop.h"
58
58
        unsigned int finished:1;
59
59
};
60
60
 
61
 
static int write_error(struct mbox_save_context *ctx)
 
61
static void write_error(struct mbox_save_context *ctx)
62
62
{
63
63
        mbox_set_syscall_error(ctx->mbox, "write()");
64
64
        ctx->failed = TRUE;
65
 
        return -1;
66
65
}
67
66
 
68
67
static int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
77
76
        }
78
77
 
79
78
        fd = ctx->mbox->mbox_fd;
80
 
        if (fstat(fd, &st) < 0)
81
 
                return mbox_set_syscall_error(ctx->mbox, "fstat()");
 
79
        if (fstat(fd, &st) < 0) {
 
80
                mbox_set_syscall_error(ctx->mbox, "fstat()");
 
81
                return -1;
 
82
        }
82
83
 
83
84
        ctx->orig_atime = st.st_atime;
84
85
 
86
87
        if (st.st_size == 0)
87
88
                return 0;
88
89
 
89
 
        if (lseek(fd, st.st_size-1, SEEK_SET) < 0)
90
 
                return mbox_set_syscall_error(ctx->mbox, "lseek()");
 
90
        if (lseek(fd, st.st_size-1, SEEK_SET) < 0) {
 
91
                mbox_set_syscall_error(ctx->mbox, "lseek()");
 
92
                return -1;
 
93
        }
91
94
 
92
 
        if (read(fd, &ch, 1) != 1)
93
 
                return mbox_set_syscall_error(ctx->mbox, "read()");
 
95
        if (read(fd, &ch, 1) != 1) {
 
96
                mbox_set_syscall_error(ctx->mbox, "read()");
 
97
                return -1;
 
98
        }
94
99
 
95
100
        if (ch != '\n') {
96
 
                if (write_full(fd, "\n", 1) < 0)
97
 
                        return write_error(ctx);
 
101
                if (write_full(fd, "\n", 1) < 0) {
 
102
                        write_error(ctx);
 
103
                        return -1;
 
104
                }
98
105
                *offset += 1;
99
106
        }
100
107
 
103
110
 
104
111
static int mbox_append_lf(struct mbox_save_context *ctx)
105
112
{
106
 
        if (o_stream_send(ctx->output, "\n", 1) < 0)
107
 
                return write_error(ctx);
 
113
        if (o_stream_send(ctx->output, "\n", 1) < 0) {
 
114
                write_error(ctx);
 
115
                return -1;
 
116
        }
108
117
 
109
118
        return 0;
110
119
}
162
171
 
163
172
        /* flush manually here so that we don't confuse seek() errors with
164
173
           buffer flushing errors */
165
 
        if (o_stream_flush(ctx->output) < 0)
166
 
                return write_error(ctx);
 
174
        if (o_stream_flush(ctx->output) < 0) {
 
175
                write_error(ctx);
 
176
                return -1;
 
177
        }
167
178
        if (o_stream_seek(ctx->output, ctx->extra_hdr_offset +
168
 
                          ctx->space_end_idx - len) < 0)
169
 
                return mbox_set_syscall_error(ctx->mbox, "o_stream_seek()");
 
179
                          ctx->space_end_idx - len) < 0) {
 
180
                mbox_set_syscall_error(ctx->mbox, "lseek()");
 
181
                return -1;
 
182
        }
170
183
 
171
184
        if (o_stream_send(ctx->output, str, len) < 0 ||
172
 
            o_stream_flush(ctx->output) < 0)
173
 
                return write_error(ctx);
 
185
            o_stream_flush(ctx->output) < 0) {
 
186
                write_error(ctx);
 
187
                return -1;
 
188
        }
174
189
 
175
 
        if (o_stream_seek(ctx->output, end_offset) < 0)
176
 
                return mbox_set_syscall_error(ctx->mbox, "o_stream_seek()");
 
190
        if (o_stream_seek(ctx->output, end_offset) < 0) {
 
191
                mbox_set_syscall_error(ctx->mbox, "lseek()");
 
192
                return -1;
 
193
        }
177
194
        return 0;
178
195
}
179
196
 
186
203
 
187
204
        /* open a new view to get the header. this is required if we just
188
205
           synced the mailbox so we can get updated next_uid. */
189
 
        (void)mail_index_refresh(mbox->box.index);
 
206
        mail_index_refresh(mbox->box.index);
190
207
        view = mail_index_view_open(mbox->box.index);
191
208
        hdr = mail_index_get_header(view);
192
209
 
268
285
        }
269
286
 
270
287
        if ((_t->flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) != 0 ||
271
 
            ctx->ctx.uid != 0)
 
288
            ctx->ctx.data.uid != 0)
272
289
                want_mail = TRUE;
273
290
 
274
291
        if (ctx->append_offset == (uoff_t)-1) {
275
292
                /* first appended mail in this transaction */
276
 
                if (mbox->mbox_lock_type != F_WRLCK) {
277
 
                        if (mbox->mbox_lock_type == F_RDLCK) {
278
 
                                /* FIXME: we shouldn't fail here. it's just
279
 
                                   a locking issue that should be possible to
280
 
                                   fix.. */
281
 
                                mail_storage_set_error(storage,
282
 
                                        MAIL_ERROR_NOTPOSSIBLE,
283
 
                                        "Can't copy mails inside same mailbox");
284
 
                                return -1;
285
 
                        }
286
 
                        if (mbox_lock(mbox, F_WRLCK, &t->mbox_lock_id) <= 0)
 
293
                if (t->write_lock_id == 0) {
 
294
                        if (mbox_lock(mbox, F_WRLCK, &t->write_lock_id) <= 0)
287
295
                                return -1;
288
296
                }
289
297
 
324
332
        return 0;
325
333
}
326
334
 
327
 
static void save_header_callback(struct message_header_line *hdr,
328
 
                                 bool *matched, struct mbox_save_context *ctx)
 
335
static void
 
336
save_header_callback(struct header_filter_istream *input ATTR_UNUSED,
 
337
                     struct message_header_line *hdr,
 
338
                     bool *matched, struct mbox_save_context *ctx)
329
339
{
330
340
        if (hdr != NULL) {
331
341
                if (strncmp(hdr->name, "From ", 5) == 0) {
440
450
int mbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
441
451
{
442
452
        struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
 
453
        struct mail_save_data *mdata = &_ctx->data;
443
454
        struct mbox_transaction_context *t =
444
455
                (struct mbox_transaction_context *)_ctx->transaction;
445
456
        enum mail_flags save_flags;
446
457
        uint64_t offset;
447
458
 
448
459
        /* FIXME: we could write timezone_offset to From-line.. */
449
 
        if (_ctx->received_date == (time_t)-1)
450
 
                _ctx->received_date = ioloop_time;
 
460
        if (mdata->received_date == (time_t)-1)
 
461
                mdata->received_date = ioloop_time;
451
462
 
452
463
        ctx->failed = FALSE;
453
464
        ctx->seq = 0;
457
468
                return -1;
458
469
        }
459
470
 
460
 
        save_flags = _ctx->flags;
461
 
        if (_ctx->uid == 0)
 
471
        save_flags = mdata->flags;
 
472
        if (mdata->uid == 0)
462
473
                save_flags |= MAIL_RECENT;
463
474
        str_truncate(ctx->headers, 0);
464
475
        if (ctx->synced) {
465
476
                if (ctx->mbox->mbox_save_md5)
466
477
                        ctx->mbox_md5_ctx = ctx->mbox->md5_v.init();
467
 
                if (ctx->next_uid < _ctx->uid) {
 
478
                if (ctx->next_uid < mdata->uid) {
468
479
                        /* we can use the wanted UID */
469
 
                        ctx->next_uid = _ctx->uid;
 
480
                        ctx->next_uid = mdata->uid;
470
481
                }
471
482
                if (ctx->output->offset == 0) {
472
483
                        /* writing the first mail. Insert X-IMAPbase as well. */
478
489
                mail_index_append(ctx->trans, ctx->next_uid, &ctx->seq);
479
490
                mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE,
480
491
                                        save_flags & ~MAIL_RECENT);
481
 
                if (_ctx->keywords != NULL) {
 
492
                if (mdata->keywords != NULL) {
482
493
                        mail_index_update_keywords(ctx->trans, ctx->seq,
483
494
                                                   MODIFY_REPLACE,
484
 
                                                   _ctx->keywords);
 
495
                                                   mdata->keywords);
485
496
                }
486
 
                if (_ctx->min_modseq != 0) {
 
497
                if (mdata->min_modseq != 0) {
487
498
                        mail_index_update_modseq(ctx->trans, ctx->seq,
488
 
                                                 _ctx->min_modseq);
 
499
                                                 mdata->min_modseq);
489
500
                }
490
501
 
491
502
                offset = ctx->output->offset == 0 ? 0 :
505
516
                mail_set_seq_saving(_ctx->dest_mail, ctx->seq);
506
517
        }
507
518
        mbox_save_append_flag_headers(ctx->headers, save_flags);
508
 
        mbox_save_append_keyword_headers(ctx, _ctx->keywords);
 
519
        mbox_save_append_keyword_headers(ctx, mdata->keywords);
509
520
        str_append_c(ctx->headers, '\n');
510
521
 
511
522
        i_assert(ctx->mbox->mbox_lock_type == F_WRLCK);
514
525
        ctx->eoh_offset = (uoff_t)-1;
515
526
        ctx->last_char = '\n';
516
527
 
517
 
        if (write_from_line(ctx, _ctx->received_date, _ctx->from_envelope) < 0)
 
528
        if (write_from_line(ctx, mdata->received_date, mdata->from_envelope) < 0)
518
529
                ctx->failed = TRUE;
519
530
        else
520
531
                ctx->input = mbox_save_get_input_stream(ctx, input);
528
539
 
529
540
        data = i_stream_get_data(ctx->input, &size);
530
541
        if (size > 0) {
531
 
                if (o_stream_send(ctx->output, data, size) < 0)
532
 
                        return write_error(ctx);
 
542
                if (o_stream_send(ctx->output, data, size) < 0) {
 
543
                        write_error(ctx);
 
544
                        return -1;
 
545
                }
533
546
                ctx->last_char = data[size-1];
534
547
                i_stream_skip(ctx->input, size);
535
548
        }
564
577
        /* append our own headers and ending empty line */
565
578
        ctx->extra_hdr_offset = ctx->output->offset;
566
579
        if (o_stream_send(ctx->output, str_data(ctx->headers),
567
 
                          str_len(ctx->headers)) < 0)
568
 
                return write_error(ctx);
 
580
                          str_len(ctx->headers)) < 0) {
 
581
                write_error(ctx);
 
582
                return -1;
 
583
        }
569
584
        ctx->eoh_offset = ctx->output->offset;
570
585
        return 0;
571
586
}
602
617
                if (i != size) {
603
618
                        /* found end of headers. write the rest of them
604
619
                           (not including the finishing empty line) */
605
 
                        if (o_stream_send(ctx->output, data, i) < 0)
606
 
                                return write_error(ctx);
 
620
                        if (o_stream_send(ctx->output, data, i) < 0) {
 
621
                                write_error(ctx);
 
622
                                return -1;
 
623
                        }
607
624
                        ctx->last_char = '\n';
608
625
                        i_stream_skip(ctx->input, i + 1);
609
626
                        break;
610
627
                }
611
628
 
612
 
                if (o_stream_send(ctx->output, data, size) < 0)
613
 
                        return write_error(ctx);
 
629
                if (o_stream_send(ctx->output, data, size) < 0) {
 
630
                        write_error(ctx);
 
631
                        return -1;
 
632
                }
614
633
                ctx->last_char = data[size-1];
615
634
                i_stream_skip(ctx->input, size);
616
635
        }
617
636
        if (ret == 0)
618
637
                return 0;
 
638
        if (ctx->input->stream_errno != 0) {
 
639
                i_error("read(%s) failed: %m", i_stream_get_name(ctx->input));
 
640
                ctx->failed = TRUE;
 
641
                return -1;
 
642
        }
619
643
 
620
644
        i_assert(ctx->last_char == '\n');
621
645
 
660
684
 
661
685
        if (ctx->output != NULL) {
662
686
                /* make sure everything is written */
663
 
                if (o_stream_flush(ctx->output) < 0)
 
687
                if (o_stream_nfinish(ctx->output) < 0)
664
688
                        write_error(ctx);
665
689
        }
666
690
 
667
691
        ctx->finished = TRUE;
668
692
        if (!ctx->failed) {
 
693
                i_assert(ctx->output != NULL);
669
694
                T_BEGIN {
670
695
                        if (mbox_write_content_length(ctx) < 0 ||
671
696
                            mbox_append_lf(ctx) < 0)
675
700
 
676
701
        if (ctx->ctx.dest_mail != NULL) {
677
702
                index_mail_cache_parse_deinit(ctx->ctx.dest_mail,
678
 
                                              ctx->ctx.received_date,
 
703
                                              ctx->ctx.data.received_date,
679
704
                                              !ctx->failed);
680
705
        }
681
706
        if (ctx->input != NULL)
683
708
 
684
709
        if (ctx->failed && ctx->mail_offset != (uoff_t)-1) {
685
710
                /* saving this mail failed - truncate back to beginning of it */
686
 
                (void)o_stream_flush(ctx->output);
 
711
                (void)o_stream_nfinish(ctx->output);
687
712
                if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->mail_offset) < 0)
688
713
                        mbox_set_syscall_error(ctx->mbox, "ftruncate()");
689
 
                o_stream_seek(ctx->output, ctx->mail_offset);
 
714
                (void)o_stream_seek(ctx->output, ctx->mail_offset);
690
715
                ctx->mail_offset = (uoff_t)-1;
691
716
        }
692
717
 
 
718
        if (ctx->seq != 0 && ctx->failed) {
 
719
                mail_index_expunge(ctx->trans, ctx->seq);
 
720
                /* currently we can't just drop pending cache updates for this
 
721
                   one specific record, so we'll reset the whole cache
 
722
                   transaction. */
 
723
                mail_cache_transaction_reset(ctx->ctx.transaction->cache_trans);
 
724
        }
693
725
        index_save_context_free(_ctx);
694
726
        return ctx->failed ? -1 : 0;
695
727
}
721
753
        /* failed, truncate file back to original size. output stream needs to
722
754
           be flushed before truncating so unref() won't write anything. */
723
755
        if (ctx->output != NULL)
724
 
                o_stream_flush(ctx->output);
 
756
                (void)o_stream_flush(ctx->output);
725
757
 
726
758
        if (ftruncate(ctx->mbox->mbox_fd, (off_t)ctx->append_offset) < 0)
727
759
                mbox_set_syscall_error(ctx->mbox, "ftruncate()");
776
808
 
777
809
        if (ctx->output != NULL) {
778
810
                /* flush the final LF */
779
 
                o_stream_flush(ctx->output);
 
811
                if (o_stream_nfinish(ctx->output) < 0)
 
812
                        write_error(ctx);
780
813
        }
781
814
        if (mbox->mbox_fd != -1 && !mbox->mbox_writeonly &&
782
815
            mbox->storage->storage.set->parsed_fsync_mode != FSYNC_MODE_NEVER) {