Mercurial > dovecot > core-2.2
view src/lib-storage/index/dbox/dbox-mail.c @ 4322:f693898fee3b HEAD
Several dbox fixes backported from branch_1_0
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 08 Jun 2006 20:14:00 +0300 |
parents | bd519db7f6e5 |
children | b445c43d5472 |
line wrap: on
line source
/* Copyright (C) 2005 Timo Sirainen */ #include "lib.h" #include "hex-dec.h" #include "read-full.h" #include "istream.h" #include "index-mail.h" #include "dbox-file.h" #include "dbox-sync.h" #include "dbox-storage.h" #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> static int dbox_mail_parse_mail_header(struct index_mail *mail, struct dbox_file *file) { struct dbox_mailbox *mbox = (struct dbox_mailbox *)mail->mail.mail.box; const struct dbox_mail_header *hdr = &file->seeked_mail_header; uint32_t hdr_uid = hex2dec(hdr->uid_hex, sizeof(hdr->uid_hex)); if (hdr_uid != mail->mail.mail.uid) { mail_storage_set_critical(STORAGE(mbox->storage), "dbox %s: Cached file offset broken", mbox->file->path); /* make sure we get it fixed */ (void)dbox_sync(mbox, TRUE); return -1; } /* Note that the mail may already have an expunge flag, but we don't care since we can still read it */ mail->data.physical_size = mail->data.virtual_size = hex2dec(hdr->mail_size_hex, sizeof(hdr->mail_size_hex)); mail->data.received_date = hex2dec(hdr->received_time_hex, sizeof(hdr->received_time_hex)); return 1; } int dbox_mail_lookup_offset(struct index_transaction_context *trans, uint32_t seq, uint32_t *file_seq_r, uoff_t *offset_r) { struct dbox_mailbox *mbox = (struct dbox_mailbox *)trans->ibox; bool synced = FALSE; int ret; for (;;) { ret = dbox_file_lookup_offset(mbox, trans->trans_view, seq, file_seq_r, offset_r); if (ret <= 0) return ret; if (*file_seq_r != 0) return 1; /* lost file sequence/offset */ if (synced) return -1; mail_storage_set_critical(STORAGE(mbox->storage), "Cached message offset lost for seq %u in " "dbox %s", seq, mbox->path); /* resync and try again */ if (dbox_sync(mbox, TRUE) < 0) return -1; synced = TRUE; } } static bool dbox_mail_try_open(struct index_mail *mail, uint32_t *file_seq_r, uoff_t *offset_r, int *ret_r) { struct dbox_mailbox *mbox = (struct dbox_mailbox *)mail->ibox; uint32_t seq = mail->mail.mail.seq; *ret_r = dbox_mail_lookup_offset(mail->trans, seq, file_seq_r, offset_r); if (*ret_r <= 0) { if (*ret_r == 0) mail->mail.mail.expunged = TRUE; return TRUE; } if ((*ret_r = dbox_file_seek(mbox, *file_seq_r, *offset_r)) < 0) return TRUE; if (*ret_r > 0) { /* ok */ *ret_r = dbox_mail_parse_mail_header(mail, mbox->file); return TRUE; } return FALSE; } static int dbox_mail_open(struct index_mail *mail, uoff_t *offset_r) { struct dbox_mailbox *mbox = (struct dbox_mailbox *)mail->ibox; uint32_t file_seq, prev_file_seq = 0; uoff_t prev_offset = 0; int i, ret; if (mail->mail.mail.expunged) return 0; for (i = 0; i < 3; i++) { if (dbox_mail_try_open(mail, &file_seq, offset_r, &ret)) return ret; if (prev_file_seq == file_seq && prev_offset == *offset_r) { /* broken offset */ break; } else { /* mail was moved. resync dbox to find out the new offset and try again. */ if (dbox_sync(mbox, FALSE) < 0) return -1; } prev_file_seq = file_seq; prev_offset = *offset_r; } mail_storage_set_critical(STORAGE(mbox->storage), "Cached message offset (%u, %"PRIuUOFF_T") " "broken for uid %u in dbox %s", file_seq, *offset_r, mail->mail.mail.uid, mbox->path); if (dbox_sync(mbox, TRUE) < 0) return -1; if (dbox_mail_try_open(mail, &file_seq, offset_r, &ret)) return ret; return -1; } static time_t dbox_mail_get_received_date(struct mail *_mail) { struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; uoff_t offset; (void)index_mail_get_received_date(_mail); if (data->received_date != (time_t)-1) return data->received_date; if (dbox_mail_open(mail, &offset) <= 0) return (time_t)-1; if (data->received_date == (time_t)-1) { /* it's broken and conflicts with our "not found" return value. change it. */ data->received_date = 0; } index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE, &data->received_date, sizeof(data->received_date)); return data->received_date; } static uoff_t dbox_mail_get_physical_size(struct mail *_mail) { struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; uoff_t offset; (void)index_mail_get_physical_size(_mail); if (data->physical_size != (uoff_t)-1) return data->physical_size; if (dbox_mail_open(mail, &offset) <= 0) return (uoff_t)-1; index_mail_cache_add(mail, MAIL_CACHE_PHYSICAL_FULL_SIZE, &data->physical_size, sizeof(data->physical_size)); return data->physical_size; } static struct istream * dbox_mail_get_stream(struct mail *_mail, struct message_size *hdr_size, struct message_size *body_size) { struct index_mail *mail = (struct index_mail *)_mail; struct dbox_mailbox *mbox = (struct dbox_mailbox *)mail->ibox; uoff_t offset; if (mail->data.stream == NULL) { if (dbox_mail_open(mail, &offset) <= 0) return NULL; offset += mbox->file->mail_header_size; mail->data.stream = i_stream_create_limit(default_pool, mbox->file->input, offset, mbox->file->seeked_mail_size); } return index_mail_init_stream(mail, hdr_size, body_size); } struct mail_vfuncs dbox_mail_vfuncs = { index_mail_free, index_mail_set_seq, index_mail_set_uid, index_mail_get_flags, index_mail_get_keywords, index_mail_get_parts, dbox_mail_get_received_date, index_mail_get_date, dbox_mail_get_physical_size, /* physical = virtual in our case */ dbox_mail_get_physical_size, index_mail_get_first_header, index_mail_get_headers, index_mail_get_header_stream, dbox_mail_get_stream, index_mail_get_special, index_mail_update_flags, index_mail_update_keywords, index_mail_expunge };