static void mail_log_action_add_group(struct mail_log_transaction_context *lt, struct mail *mail, enum mail_log_event event, const char *data) { struct mail_log_group_changes *group; uoff_t size; group = mail_log_action_get_group(lt, event, data); if ((mail_log_set.fields & MAIL_LOG_FIELD_UID) != 0) { if (!array_is_created(&group->uids)) p_array_init(&group->uids, lt->pool, 32); if (event != MAIL_LOG_EVENT_SAVE_FINISH) seq_range_array_add(&group->uids, 0, mail->uid); } if ((mail_log_set.fields & MAIL_LOG_FIELD_PSIZE) != 0 && (event & (MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY)) != 0) { if (mail_get_physical_size(mail, &size) == 0) group->psize_total += size; } if ((mail_log_set.fields & MAIL_LOG_FIELD_VSIZE) != 0 && (event & (MAIL_LOG_EVENT_EXPUNGE | MAIL_LOG_EVENT_COPY)) != 0) { if (mail_get_virtual_size(mail, &size) == 0) group->vsize_total += size; } }
static int pop3_mail_get_size(struct client *client, struct mail *mail, uoff_t *size_r) { int ret; if (!client->set->pop3_fast_size_lookups) return mail_get_virtual_size(mail, size_r); /* first try to get the virtual size */ mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL; ret = mail_get_virtual_size(mail, size_r); mail->lookup_abort = MAIL_LOOKUP_ABORT_NEVER; if (ret == 0) return 0; if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_NOTPOSSIBLE) return -1; /* virtual size not available with a fast lookup. fallback to trying the physical size */ mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL; ret = mail_get_physical_size(mail, size_r); mail->lookup_abort = MAIL_LOOKUP_ABORT_NEVER; if (ret == 0) return 0; if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_NOTPOSSIBLE) return -1; /* no way to quickly get the size. fallback to doing a slow virtual size lookup */ return mail_get_virtual_size(mail, size_r); }
static int quota_count_mailbox(struct quota_root *root, struct mail_namespace *ns, const char *vname, uint64_t *bytes_r, uint64_t *count_r) { struct quota_rule *rule; struct mailbox *box; struct mailbox_transaction_context *trans; struct mail_search_context *ctx; struct mail *mail; struct mail_search_args *search_args; enum mail_error error; uoff_t size; int ret = 0; rule = quota_root_rule_find(root->set, vname); if (rule != NULL && rule->ignore) { /* mailbox not included in quota */ return 0; } box = mailbox_alloc(ns->list, vname, MAILBOX_FLAG_READONLY); if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { error = mailbox_get_last_mail_error(box); mailbox_free(&box); if (error == MAIL_ERROR_TEMP) return -1; /* non-temporary error, e.g. ACLs denied access. */ return 0; } trans = mailbox_transaction_begin(box, 0); search_args = mail_search_build_init(); mail_search_build_add_all(search_args); ctx = mailbox_search_init(trans, search_args, NULL, MAIL_FETCH_PHYSICAL_SIZE, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(ctx, &mail)) { if (mail_get_physical_size(mail, &size) == 0) *bytes_r += size; *count_r += 1; } if (mailbox_search_deinit(&ctx) < 0) ret = -1; if (ret < 0) mailbox_transaction_rollback(&trans); else (void)mailbox_transaction_commit(&trans); mailbox_free(&box); return ret; }
static int virtual_mail_get_physical_size(struct mail *mail, uoff_t *size_r) { struct virtual_mail *vmail = (struct virtual_mail *)mail; if (virtual_mail_handle_lost(vmail) < 0) return -1; if (mail_get_physical_size(vmail->backend_mail, size_r) < 0) { virtual_box_copy_error(mail->box, vmail->backend_mail->box); return -1; } return 0; }
static bool i_stream_mail_try_get_cached_size(struct mail_istream *mstream) { struct mail *mail = mstream->mail; enum mail_lookup_abort orig_lookup_abort; if (mstream->expected_size != (uoff_t)-1) return TRUE; orig_lookup_abort = mail->lookup_abort; mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE; if (mail_get_physical_size(mail, &mstream->expected_size) < 0) mstream->expected_size = (uoff_t)-1; mail->lookup_abort = orig_lookup_abort; return mstream->expected_size != (uoff_t)-1; }
static int fetch_body(struct imap_fetch_context *ctx, struct mail *mail, const struct imap_fetch_body_data *body) { const struct message_size *fetch_size; struct istream *input; struct message_size hdr_size, body_size; if (body->section[0] == '\0') { if (mail_get_stream(mail, NULL, NULL, &input) < 0 || mail_get_virtual_size(mail, &body_size.virtual_size) < 0 || mail_get_physical_size(mail, &body_size.physical_size) < 0) return -1; } else { if (mail_get_stream(mail, &hdr_size, body->section[0] == 'H' ? NULL : &body_size, &input) < 0) return -1; } ctx->cur_input = input; i_stream_ref(ctx->cur_input); ctx->update_partial = TRUE; switch (body->section[0]) { case '\0': /* BODY[] - fetch everything */ fetch_size = &body_size; ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE; break; case 'H': /* BODY[HEADER] - fetch only header */ fetch_size = &hdr_size; ctx->cur_size_field = MAIL_FETCH_MESSAGE_PARTS; break; case 'T': /* BODY[TEXT] - skip header */ i_stream_skip(ctx->cur_input, hdr_size.physical_size); fetch_size = &body_size; ctx->cur_size_field = MAIL_FETCH_VIRTUAL_SIZE; break; default: i_unreached(); } return fetch_data(ctx, body, fetch_size); }
static int imap_map_read(struct mailbox *box) { struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box); struct mailbox_status status; struct mailbox_transaction_context *t; struct mail_search_args *search_args; struct mail_search_context *ctx; struct mail *mail; struct imap_msg_map *map; uoff_t psize; int ret = 0; mailbox_get_open_status(box, STATUS_MESSAGES, &status); i_assert(!array_is_created(&mbox->imap_msg_map)); p_array_init(&mbox->imap_msg_map, box->pool, status.messages); t = mailbox_transaction_begin(box, 0); search_args = mail_search_build_init(); mail_search_build_add_all(search_args); ctx = mailbox_search_init(t, search_args, NULL, MAIL_FETCH_PHYSICAL_SIZE, NULL); mail_search_args_unref(&search_args); while (mailbox_search_next(ctx, &mail)) { if (mail_get_physical_size(mail, &psize) < 0) { i_error("pop3_migration: Failed to get psize for imap uid %u: %s", mail->uid, mailbox_get_last_error(box, NULL)); ret = -1; break; } map = array_append_space(&mbox->imap_msg_map); map->uid = mail->uid; map->psize = psize; } if (mailbox_search_deinit(&ctx) < 0) ret = -1; (void)mailbox_transaction_commit(&t); return ret; }
static void index_mail_get_cached_body_size(struct index_mail *mail) { struct index_mail_data *data = &mail->data; uoff_t tmp; if (!data->hdr_size_set) return; /* we've already called get_cached_msgpart_sizes() and it didn't work. try to do this by using cached virtual size and a quick physical size lookup. */ if (!index_mail_get_cached_virtual_size(mail, &tmp)) return; if (!data->body_size_set) { if (mail_get_physical_size(&mail->mail.mail, &tmp) < 0) return; /* we should have everything now. try again. */ (void)index_mail_get_cached_virtual_size(mail, &tmp); } }
static void mail_log_append_mail_message_real(struct mail_log_mail_txn_context *ctx, struct mail *mail, enum mail_log_event event, const char *desc) { struct mail_log_user *muser = MAIL_LOG_USER_CONTEXT(mail->box->storage->user); struct mail_log_message *msg; string_t *text; uoff_t size; msg = p_new(ctx->pool, struct mail_log_message, 1); text = t_str_new(128); str_append(text, desc); str_append(text, ": "); if ((muser->fields & MAIL_LOG_FIELD_BOX) != 0) { mail_log_append_mailbox_name(text, mail); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_UID) != 0) { if (event != MAIL_LOG_EVENT_SAVE && event != MAIL_LOG_EVENT_COPY) mail_log_append_uid(ctx, msg, text, mail->uid); else { /* with mbox mail->uid contains the uid, but handle this consistently with all mailbox formats */ mail_log_append_uid(ctx, msg, text, 0); } str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_MSGID) != 0) { mail_log_append_mail_header(text, mail, "msgid", "Message-ID"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_PSIZE) != 0) { if (mail_get_physical_size(mail, &size) == 0) str_printfa(text, "size=%"PRIuUOFF_T, size); else str_printfa(text, "size=error"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_VSIZE) != 0) { if (mail_get_virtual_size(mail, &size) == 0) str_printfa(text, "vsize=%"PRIuUOFF_T, size); else str_printfa(text, "vsize=error"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_FROM) != 0) { mail_log_append_mail_header(text, mail, "from", "From"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_SUBJECT) != 0) { mail_log_append_mail_header(text, mail, "subject", "Subject"); str_append(text, ", "); } if ((muser->fields & MAIL_LOG_FIELD_FLAGS) != 0) { str_printfa(text, "flags=("); imap_write_flags(text, mail_get_flags(mail), mail_get_keywords(mail)); str_append(text, "), "); } str_truncate(text, str_len(text)-2); msg->event = event; msg->text = p_strdup(ctx->pool, str_c(text)); DLLIST2_APPEND(&ctx->messages, &ctx->messages_tail, msg); }
static int maildir_copy_hardlink(struct mail_save_context *ctx, struct mail *mail) { struct maildir_mailbox *dest_mbox = (struct maildir_mailbox *)ctx->transaction->box; struct maildir_mailbox *src_mbox; struct maildir_filename *mf; struct hardlink_ctx do_ctx; const char *path, *guid, *dest_fname; uoff_t vsize, size; enum mail_lookup_abort old_abort; if (strcmp(mail->box->storage->name, MAILDIR_STORAGE_NAME) == 0) src_mbox = (struct maildir_mailbox *)mail->box; else if (strcmp(mail->box->storage->name, "raw") == 0) { /* lda uses raw format */ src_mbox = NULL; } else { /* Can't hard link files from the source storage */ return 0; } /* hard link to tmp/ with a newly generated filename and later when we have uidlist locked, move it to new/cur. */ dest_fname = maildir_filename_generate(); memset(&do_ctx, 0, sizeof(do_ctx)); do_ctx.dest_path = t_strdup_printf("%s/tmp/%s", mailbox_get_path(&dest_mbox->box), dest_fname); if (src_mbox != NULL) { /* maildir */ if (maildir_file_do(src_mbox, mail->uid, do_hardlink, &do_ctx) < 0) return -1; } else { /* raw / lda */ if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME, &path) < 0 || *path == '\0') return 0; if (do_hardlink(dest_mbox, path, &do_ctx) < 0) return -1; } if (!do_ctx.success) { /* couldn't copy with hardlinking, fallback to copying */ return 0; } /* hardlinked to tmp/, treat as normal copied mail */ mf = maildir_save_add(ctx, dest_fname, mail); if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) == 0) { if (*guid != '\0') maildir_save_set_dest_basename(ctx, mf, guid); } /* remember size/vsize if possible */ old_abort = mail->lookup_abort; mail->lookup_abort = MAIL_LOOKUP_ABORT_READ_MAIL; if (mail_get_physical_size(mail, &size) < 0) size = (uoff_t)-1; if (mail_get_virtual_size(mail, &vsize) < 0) vsize = (uoff_t)-1; maildir_save_set_sizes(mf, size, vsize); mail->lookup_abort = old_abort; return 1; }