static int maildir_mail_get_physical_size(struct mail *_mail, uoff_t *size_r) { struct index_mail *mail = (struct index_mail *)_mail; struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box; struct index_mail_data *data = &mail->data; struct stat st; const char *path; int ret; if (maildir_uidlist_is_read(mbox->uidlist) || (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) { /* try to get the size from uidlist (see virtual size above) */ if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0) return -1; } if (data->physical_size == (uoff_t)-1) { if (index_mail_get_physical_size(_mail, size_r) == 0) { i_assert(mail->data.physical_size != (uoff_t)-1); maildir_handle_size_caching(mail, TRUE, FALSE); return 0; } if (maildir_quick_size_lookup(mail, FALSE, &data->physical_size) < 0) return -1; } if (data->physical_size != (uoff_t)-1) { data->dont_cache_fetch_fields |= MAIL_FETCH_PHYSICAL_SIZE; *size_r = data->physical_size; return 0; } if (!_mail->saving) { ret = maildir_file_do(mbox, _mail->uid, do_stat, &st); if (ret <= 0) { if (ret == 0) mail_set_expunged(_mail); return -1; } } else { /* saved mail which hasn't been committed yet */ path = maildir_save_file_get_path(_mail->transaction, _mail->seq); if (stat(path, &st) < 0) { mail_storage_set_critical(_mail->box->storage, "stat(%s) failed: %m", path); return -1; } } data->physical_size = st.st_size; maildir_handle_size_caching(mail, FALSE, FALSE); *size_r = st.st_size; return 0; }
static int maildir_mail_get_virtual_size(struct mail *_mail, uoff_t *size_r) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)_mail->box; struct index_mail *mail = (struct index_mail *)_mail; struct index_mail_data *data = &mail->data; struct message_size hdr_size, body_size; struct istream *input; uoff_t old_offset; if (maildir_uidlist_is_read(mbox->uidlist) || (_mail->box->flags & MAILBOX_FLAG_POP3_SESSION) != 0) { /* try to get the size from uidlist. this is especially useful with pop3 to avoid unnecessarily opening the cache file. */ if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0) return -1; } if (data->virtual_size == (uoff_t)-1) { if (index_mail_get_cached_virtual_size(mail, size_r)) { i_assert(mail->data.virtual_size != (uoff_t)-1); maildir_handle_size_caching(mail, TRUE, TRUE); return 0; } if (maildir_quick_size_lookup(mail, TRUE, &data->virtual_size) < 0) return -1; } if (data->virtual_size != (uoff_t)-1) { data->dont_cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE; *size_r = data->virtual_size; return 0; } /* fallback to reading the file */ old_offset = data->stream == NULL ? 0 : data->stream->v_offset; if (mail_get_stream(_mail, &hdr_size, &body_size, &input) < 0) return -1; i_stream_seek(data->stream, old_offset); maildir_handle_size_caching(mail, FALSE, TRUE); *size_r = data->virtual_size; return 0; }
static void maildir_handle_size_caching(struct index_mail *mail, bool quick_check, bool vsize) { struct mailbox *box = mail->mail.mail.box; struct maildir_mailbox *mbox = (struct maildir_mailbox *)box; enum mail_fetch_field field; uoff_t size; int pop3_state; field = vsize ? MAIL_FETCH_VIRTUAL_SIZE : MAIL_FETCH_PHYSICAL_SIZE; if ((mail->data.dont_cache_fetch_fields & field) != 0) return; if (quick_check && maildir_quick_size_lookup(mail, vsize, &size) > 0) { /* already in filename / uidlist. don't add it anywhere, including to the uidlist if it's already in filename. do some extra checks here to catch potential cache bugs. */ if (vsize && mail->data.virtual_size != size) { mail_cache_set_corrupted(box->cache, "Corrupted virtual size for uid=%u: " "%"PRIuUOFF_T" != %"PRIuUOFF_T, mail->mail.mail.uid, mail->data.virtual_size, size); mail->data.virtual_size = size; } else if (!vsize && mail->data.physical_size != size) { mail_cache_set_corrupted(box->cache, "Corrupted physical size for uid=%u: " "%"PRIuUOFF_T" != %"PRIuUOFF_T, mail->mail.mail.uid, mail->data.physical_size, size); mail->data.physical_size = size; } mail->data.dont_cache_fetch_fields |= field; return; } /* 1 = pop3-only, 0 = mixed, -1 = no pop3 */ pop3_state = maildir_get_pop3_state(mail); if (pop3_state >= 0 && mail->mail.mail.uid != 0) { /* if size is wanted permanently, store it to uidlist so that in case cache file gets lost we can get it quickly */ mail->data.dont_cache_fetch_fields |= field; size = vsize ? mail->data.virtual_size : mail->data.physical_size; maildir_uidlist_set_ext(mbox->uidlist, mail->mail.mail.uid, vsize ? MAILDIR_UIDLIST_REC_EXT_VSIZE : MAILDIR_UIDLIST_REC_EXT_PSIZE, dec2str(size)); } }