mbox-fsck.c revision d14de73e30d5d0e06a5b28508b6a44e888edd2d1
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned char *msg;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen while (io_buffer_read_data_blocking(inbuf, &msg, &size, 0) > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < size; i++) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int verify_header_md5sum(MailIndex *index, MailIndexRecord *rec,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen const unsigned char *old_digest;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen /* MD5 sums must match */
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen old_digest = index->lookup_field_raw(index, rec, FIELD_TYPE_MD5, &size);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic int verify_end_of_body(IOBuffer *inbuf, uoff_t end_offset)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen unsigned char *data;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* don't bother parsing the whole body, just make
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen sure it ends properly */
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen /* end of file. a bit unexpected though,
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen since \n is missing. */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* read forward a bit */
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (io_buffer_read_data_blocking(inbuf, &data, &size, 6) < 0)
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen /* either there should be the next From-line,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen or [\r]\n at end of file */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return size == 0 || (size >= 5 && strncmp(data, "From ", 5) == 0);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic int mail_update_header_size(MailIndex *index, MailIndexRecord *rec,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* update index record */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if ((rec->cached_fields & FIELD_TYPE_MESSAGEPART) == 0)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen /* update FIELD_TYPE_MESSAGEPART */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen part_data = index->lookup_field_raw(index, rec, FIELD_TYPE_MESSAGEPART,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* well, this wasn't expected but don't bother failing */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* copy & update the part data */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (!message_part_serialize_update_header(part_data_copy, size,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen index->update_field_raw(update, FIELD_TYPE_MESSAGEPART,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int match_next_record(MailIndex *index, MailIndexRecord *rec,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* skip the From-line */
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen /* possibly broken message, find the From-line to make sure
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen header parser won't pass it. */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen io_buffer_set_read_limit(inbuf, inbuf->offset);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* get the MD5 sum of fixed headers and the current message flags
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen in Status and X-Status fields */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen message_parse_header(NULL, inbuf, &hdr_size, mbox_header_func, &ctx);
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen if (verify_header_md5sum(index, rec, current_digest) &&
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen verify_end_of_body(inbuf, body_offset + rec->body_size)) {
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen /* valid message */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen /* update flags, unless we've changed them */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen if ((rec->index_flags & INDEX_MAIL_FLAG_DIRTY) == 0) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* update_flags() sets dirty flag, remove it */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* update location */
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen if (!mbox_mail_get_start_offset(index, rec, &offset))
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen /* update size */
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (rec->header_size != hdr_size.physical_size ) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen /* try next message */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int mbox_index_fsck_buf(MailIndex *index, IOBuffer *inbuf)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen unsigned char *data;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen unsigned int seq;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen /* first make sure we start with a "From " line. If file is too
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen small, we'll just treat it as empty mbox file. */
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (io_buffer_read_data_blocking(inbuf, &data, &size, 5) > 0 &&
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen index_set_error(index, "File isn't in mbox format: %s",
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen /* we'll go through the mailbox and index in order matching the
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen messages by their size and Message-ID. old mails aren't remembered,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen so we handle well only the cases when mail has been deleted. if
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen mails have been reordered (eg. sorted by someone) most of the mails
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen will show up as being new. if we really wanted to support that well,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen we could save the message-ids into hash but I don't know if it's
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen worth the trouble. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* we're at the [\r]\n before the From-line,
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* they just went and broke it, even while
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen we had it locked. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (!match_next_record(index, rec, seq, inbuf, &rec, &dirty))
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* Get back to line before From */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* delete the rest of the records */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (!dirty && (index->header->flags & MAIL_INDEX_FLAG_DIRTY_MESSAGES)) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen /* no flags were dirty anymore, no need to rewrite */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen index->header->flags &= ~MAIL_INDEX_FLAG_DIRTY_MESSAGES;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen /* open the mbox file. we don't really need to open it read-write,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen but fcntl() locking requires it. */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return mbox_set_syscall_error(index, "open()");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen inbuf = io_buffer_create_mmap(fd, default_pool,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen if (!mbox_lock(index, index->mbox_path, fd, FALSE))
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen (void)mbox_unlock(index, index->mbox_path, fd);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* check the header */