bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "lib.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "array.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "istream.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "ostream.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "str.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "hash.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "dbox-attachment.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "mdbox-storage.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "mdbox-storage-rebuild.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "mdbox-file.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "mdbox-map.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "mdbox-sync.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <dirent.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen/*
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen Altmoving works like:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen 1. Message's DBOX_INDEX_FLAG_ALT flag is changed. This is caught by mdbox
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen code and map UID's alt-refcount is updated. It won't be written to disk.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen 2. mdbox_purge() is called, which checks if map UID's refcount equals
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen to its alt-refcount. If it does, it's moved to alt storage. Moving to
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen primary storage is done if _ALT flag was removed from any message.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen*/
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenenum mdbox_msg_action {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen MDBOX_MSG_ACTION_MOVE_TO_ALT = 1,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen MDBOX_MSG_ACTION_MOVE_FROM_ALT
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen};
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstruct mdbox_purge_context {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen pool_t pool;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uint32_t lowest_primary_file_id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* list of file_ids that exist in primary storage. this list is looked
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen up while there is no locking, so it may not be accurate anymore by
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen the time it's used. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ARRAY_TYPE(seq_range) primary_file_ids;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* list of file_ids that we need to purge */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ARRAY_TYPE(seq_range) purge_file_ids;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen /* uint32_t map_uid => enum mdbox_msg_action action */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(void *, void *) altmoves;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen bool have_altmoves;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen struct mdbox_map_atomic_context *atomic;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map_append_context *append_ctx;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen};
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainenstatic int mdbox_map_file_msg_offset_cmp(const struct mdbox_map_file_msg *m1,
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen const struct mdbox_map_file_msg *m2)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (m1->offset < m2->offset)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else if (m1->offset > m2->offset)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_file_read_metadata_hdr(struct dbox_file *file,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_metadata_header *meta_hdr_r)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const unsigned char *data;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen size_t size;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
d868a04630bd7bfe9c1543a7c3f68703b3e276e4Timo Sirainen ret = i_stream_read_bytes(file->input, &data, &size,
d868a04630bd7bfe9c1543a7c3f68703b3e276e4Timo Sirainen sizeof(*meta_hdr_r));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret <= 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(ret == -1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (file->input->stream_errno == 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file, "missing metadata");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(&file->storage->storage,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen "read(%s) failed: %s", file->cur_path,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen i_stream_get_error(file->input));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen memcpy(meta_hdr_r, data, sizeof(*meta_hdr_r));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (memcmp(meta_hdr_r->magic_post, DBOX_MAGIC_POST,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen sizeof(meta_hdr_r->magic_post)) != 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file, "invalid metadata magic");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_stream_skip(file->input, sizeof(*meta_hdr_r));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return 1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_file_metadata_copy(struct dbox_file *file, struct ostream *output)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_metadata_header meta_hdr;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *line;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen size_t buf_size;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((ret = mdbox_file_read_metadata_hdr(file, &meta_hdr)) <= 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, &meta_hdr, sizeof(meta_hdr));
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen buf_size = i_stream_get_max_buffer_size(file->input);
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen /* use unlimited line length for metadata */
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen i_stream_set_max_buffer_size(file->input, (size_t)-1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while ((line = i_stream_read_next_line(file->input)) != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (*line == '\0') {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* end of metadata */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(output, line);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, "\n", 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_stream_set_max_buffer_size(file->input, buf_size);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (line == NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dbox_file_set_corrupted(file, "missing end-of-metadata line");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, "\n", 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return 1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_metadata_get_extrefs(struct dbox_file *file, pool_t ext_refs_pool,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ARRAY_TYPE(mail_attachment_extref) *extrefs)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_metadata_header meta_hdr;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *line;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen size_t buf_size;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* skip and ignore the header */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((ret = mdbox_file_read_metadata_hdr(file, &meta_hdr)) <= 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen buf_size = i_stream_get_max_buffer_size(file->input);
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen /* use unlimited line length for metadata */
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen i_stream_set_max_buffer_size(file->input, (size_t)-1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen while ((line = i_stream_read_next_line(file->input)) != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (*line == '\0') {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* end of metadata */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (*line == DBOX_METADATA_EXT_REF) T_BEGIN {
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (!index_attachment_parse_extrefs(line+1, ext_refs_pool,
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen extrefs)) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("%s: Ignoring corrupted extref: %s",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen file->cur_path, line);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen } T_END;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen i_stream_set_max_buffer_size(file->input, buf_size);
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (line == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file, "missing end-of-metadata line");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainenmdbox_purge_want_altpath(struct mdbox_purge_context *ctx,
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen struct dbox_file *file, uint32_t map_uid)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen enum mdbox_msg_action action;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *value;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
2795f6183049a8a4cc489869b3e866dc20a8a732Baofeng Wang if (dbox_file_is_in_alt(file))
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen return TRUE;
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!ctx->have_altmoves)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen value = hash_table_lookup(ctx->altmoves, POINTER_CAST(map_uid));
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen action = POINTER_CAST_TO(value, enum mdbox_msg_action);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return action == MDBOX_MSG_ACTION_MOVE_TO_ALT;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenmdbox_purge_save_msg(struct mdbox_purge_context *ctx, struct dbox_file *file,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen const struct mdbox_map_file_msg *msg)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct dbox_file_append_context *out_file_append;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct istream *input;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct ostream *output;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen enum mdbox_map_append_flags append_flags;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uoff_t msg_size;
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen int ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ctx->append_ctx == NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->append_ctx = mdbox_map_append_begin(ctx->atomic);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen append_flags = !mdbox_purge_want_altpath(ctx, file, msg->map_uid) ? 0 :
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen DBOX_MAP_APPEND_FLAG_ALT;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen msg_size = file->msg_header_size + file->cur_physical_size;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_append_next(ctx->append_ctx, file->cur_physical_size,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen append_flags, &out_file_append, &output) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_assert(file != out_file_append->file);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen input = i_stream_create_limit(file->input, msg_size);
6f187ae85911f63cb87271246c68f3c13a0adb7bTimo Sirainen o_stream_nsend_istream(output, input);
d1ba8ecbb936ace90179d2292952546708d68f71Timo Sirainen if (o_stream_flush(output) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(&file->storage->storage,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen "write(%s) failed: %s",
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen out_file_append->file->cur_path,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen o_stream_get_error(output));
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen ret = -1;
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen } else if (input->v_offset != msg_size) {
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen i_assert(input->v_offset < msg_size);
1bc075e2e4ed422f9590c95c3ae223422b97ce6aTimo Sirainen i_assert(i_stream_read_eof(file->input));
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen dbox_file_set_corrupted(file, "truncated message at EOF");
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen ret = 0;
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen } else {
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen ret = 1;
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen }
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen i_stream_unref(&input);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen if (ret > 0) {
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen /* copy metadata */
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen if ((ret = mdbox_file_metadata_copy(file, output)) <= 0)
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen mdbox_map_append_finish(ctx->append_ctx);
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen }
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainenstatic int
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainenmdbox_file_purge_check_refcounts(struct mdbox_purge_context *ctx,
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen const ARRAY_TYPE(mdbox_map_file_msg) *msgs_arr)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen{
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen struct mdbox_map *map = ctx->storage->map;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen struct mdbox_map_mail_index_record rec;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen uint16_t refcount;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen const struct mdbox_map_file_msg *msgs;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen unsigned int i, count;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen int ret;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen if (mdbox_map_atomic_lock(ctx->atomic, "purging check") < 0)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return -1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen msgs = array_get(msgs_arr, &count);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen for (i = 0; i < count; i++) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (msgs[i].refcount != 0)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen continue;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen ret = mdbox_map_lookup_full(map, msgs[i].map_uid, &rec,
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen &refcount);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ret <= 0) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ret < 0)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return -1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen mdbox_map_set_corrupted(map,
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen "Purging unexpectedly lost map_uid=%u",
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen msgs[i].map_uid);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return -1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (refcount > 0)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return 0;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return 1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen}
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_purge_attachments(struct mdbox_purge_context *ctx,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs_arr)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_storage *storage = &ctx->storage->storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const struct mail_attachment_extref *extref;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret = 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen array_foreach(extrefs_arr, extref) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (index_attachment_delete(&storage->storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen storage->attachment_fs,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen extref->path) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainenmdbox_file_purge(struct mdbox_purge_context *ctx, struct dbox_file *file,
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen uint32_t file_id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *dstorage = (struct mdbox_storage *)file->storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct stat st;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen ARRAY_TYPE(mdbox_map_file_msg) msgs_arr;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen const struct mdbox_map_file_msg *msgs;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ARRAY_TYPE(seq_range) expunged_map_uids;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ARRAY_TYPE(uint32_t) copied_map_uids;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ARRAY_TYPE(mail_attachment_extref) ext_refs;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen pool_t ext_refs_pool;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int i, count;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uoff_t offset;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_assert(ctx->atomic == NULL);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_assert(ctx->append_ctx == NULL);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if ((ret = dbox_file_try_lock(file)) <= 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* make sure the file still exists. another process may have already
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen deleted it. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (stat(file->cur_path, &st) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_unlock(file);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (errno == ENOENT)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(&file->storage->storage,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "stat(%s) failed: %m", file->cur_path);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* get list of map UIDs that exist in this file (again has to be done
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen after locking) */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(&msgs_arr, 128);
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen if (mdbox_map_get_file_msgs(dstorage->map, file_id,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &msgs_arr) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_free(&msgs_arr);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_unlock(file);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* sort messages by their offset */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_sort(&msgs_arr, mdbox_map_file_msg_offset_cmp);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ext_refs_pool = pool_alloconly_create("mdbox purge ext refs", 1024);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen ctx->atomic = mdbox_map_atomic_begin(ctx->storage->map);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen msgs = array_get(&msgs_arr, &count);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_array_init(&ext_refs, 32);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(&copied_map_uids, I_MIN(count, 1));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(&expunged_map_uids, I_MIN(count, 1));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen offset = file->file_header_size;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (i = 0; i < count; i++) {
a81b240cfe84231eac64084efd5b0e1e91a9e817Timo Sirainen if ((ret = dbox_file_seek(file, offset)) <= 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (msgs[i].offset != offset) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* map doesn't match file's actual contents */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "purging found mismatched offsets "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "(%"PRIuUOFF_T" vs %u, %u/%u)",
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen offset, msgs[i].offset, i, count);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (msgs[i].refcount == 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* skip over expunged message */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_stream_seek(file->input, offset +
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen file->msg_header_size +
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen file->cur_physical_size);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* skip metadata */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = mdbox_metadata_get_extrefs(file, ext_refs_pool,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen &ext_refs);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret <= 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&expunged_map_uids,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen msgs[i].map_uid);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* non-expunged message. write it to output file. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_stream_seek(file->input, offset);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen ret = mdbox_purge_save_msg(ctx, file, &msgs[i]);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen if (ret <= 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_append(&copied_map_uids, &msgs[i].map_uid, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen offset = file->input->v_offset;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (offset != (uoff_t)st.st_size && ret > 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* file has more messages than what map tells us */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "more messages available than in map "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "(%"PRIuUOFF_T" < %"PRIuUOFF_T")", offset, st.st_size);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen if (ret > 0 && ctx->append_ctx != NULL) {
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen /* flush writes before locking the map */
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen if (mdbox_map_append_flush(ctx->append_ctx) < 0)
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen ret = -1;
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret <= 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen else {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* it's possible that one of the messages we purged was
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen just copied to another mailbox. the only way to prevent that
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen would be to keep map locked during the purge, but that could
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen keep it locked for too long. instead we'll check here if
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen there are such copies, and if there are cancel this file's
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen purge. */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen ret = mdbox_file_purge_check_refcounts(ctx, &msgs_arr);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen array_free(&msgs_arr); msgs = NULL;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ret <= 0) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* failed */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen } else if (ctx->append_ctx == NULL) {
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen /* everything purged from this file */
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen ret = 1;
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* assign new file_id + offset to moved messages */
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_append_move(ctx->append_ctx, &copied_map_uids,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &expunged_map_uids) < 0 ||
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen mdbox_map_append_commit(ctx->append_ctx) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (ctx->append_ctx != NULL)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen mdbox_map_append_free(&ctx->append_ctx);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen (void)mdbox_map_atomic_finish(&ctx->atomic);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* unlink only after unlocking map, so readers don't see it
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen temporarily vanished */
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen if (ret > 0) {
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen (void)dbox_file_unlink(file);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mdbox_map_remove_file_id(ctx->storage->map, file_id) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen ret = -1;
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_unlock(file);
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_free(&copied_map_uids);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_free(&expunged_map_uids);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (void)mdbox_purge_attachments(ctx, &ext_refs);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen array_free(&ext_refs);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen pool_unref(&ext_refs_pool);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenvoid mdbox_purge_alt_flag_change(struct mail *mail, bool move_to_alt)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_mailbox *mbox = MDBOX_MAILBOX(mail->box);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ARRAY_TYPE(uint32_t) *dest;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uint32_t map_uid;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* we'll assume here that alt flag won't be changed multiple times
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for the same mail. it shouldn't happen with current code, and
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen checking for it would just slow down the code.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen so the way it works currently is just that map_uids are added to
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen an array, which is later sorted and processed further. note that
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen it's still possible that the same map_uid exists in the array
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen multiple times. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (mdbox_mail_lookup(mbox, mbox->box.view, mail->seq, &map_uid) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dest = move_to_alt ? &mbox->storage->move_to_alt_map_uids :
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen &mbox->storage->move_from_alt_map_uids;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!array_is_created(dest))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(dest, 256);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_append(dest, &map_uid, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic struct mdbox_purge_context *
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenmdbox_purge_alloc(struct mdbox_storage *storage)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_purge_context *ctx;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen pool_t pool;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen pool = pool_alloconly_create("mdbox purge context", 1024*32);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx = p_new(pool, struct mdbox_purge_context, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->pool = pool;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->storage = storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->lowest_primary_file_id = (uint32_t)-1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(&ctx->primary_file_ids, 64);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(&ctx->purge_file_ids, 64);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&ctx->altmoves, pool, 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ctx;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void mdbox_purge_free(struct mdbox_purge_context **_ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_purge_context *ctx = *_ctx;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen *_ctx = NULL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen hash_table_destroy(&ctx->altmoves);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_free(&ctx->primary_file_ids);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_free(&ctx->purge_file_ids);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen pool_unref(&ctx->pool);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int mdbox_purge_get_primary_files(struct mdbox_purge_context *ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *dstorage = ctx->storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mail_storage *storage = &dstorage->storage.storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen DIR *dir;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct dirent *d;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen string_t *path;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int file_id;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t dir_len;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!array_is_created(&dstorage->move_to_alt_map_uids) &&
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen !array_is_created(&dstorage->move_from_alt_map_uids)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* we don't need to do alt moving, don't bother getting list
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen of primary files */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dir = opendir(dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (dir == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (errno == ENOENT) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* no storage directory at all yet */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(storage,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "opendir(%s) failed: %m", dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen path = t_str_new(256);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(path, dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append_c(path, '/');
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dir_len = str_len(path);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (errno = 0; (d = readdir(dir)) != NULL; errno = 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strncmp(d->d_name, MDBOX_MAIL_FILE_PREFIX,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen strlen(MDBOX_MAIL_FILE_PREFIX)) != 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen continue;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (str_to_uint32(d->d_name + strlen(MDBOX_MAIL_FILE_PREFIX),
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen &file_id) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen continue;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_truncate(path, dir_len);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(path, d->d_name);
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&ctx->primary_file_ids, file_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (array_count(&ctx->primary_file_ids) > 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const struct seq_range *range =
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_idx(&ctx->primary_file_ids, 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->lowest_primary_file_id = range[0].seq1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (errno != 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(storage,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "readdir(%s) failed: %m", dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (closedir(dir) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(storage,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "closedir(%s) failed: %m", dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int uint32_t_cmp(const uint32_t *u1, const uint32_t *u2)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (*u1 < *u2)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (*u1 > *u2)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int mdbox_altmove_add_files(struct mdbox_purge_context *ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *dstorage = ctx->storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const uint32_t *map_uids;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int i, count, alt_refcount = 0;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map_mail_index_record cur_rec;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen enum mdbox_msg_action action;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uint32_t cur_map_uid;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uint16_t cur_refcount = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uoff_t offset;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* first add move-to-alt actions */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (array_is_created(&dstorage->move_to_alt_map_uids)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_sort(&dstorage->move_to_alt_map_uids, uint32_t_cmp);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen map_uids = array_get(&dstorage->move_to_alt_map_uids, &count);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen map_uids = NULL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen count = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen cur_map_uid = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (i = 0; i < count; i++) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (cur_map_uid != map_uids[i]) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen cur_map_uid = map_uids[i];
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_lookup_full(dstorage->map, cur_map_uid,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &cur_rec, &cur_refcount) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen cur_refcount = (uint16_t)-1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen alt_refcount = 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen alt_refcount++;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (alt_refcount == cur_refcount &&
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen seq_range_exists(&ctx->primary_file_ids, cur_rec.file_id)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* all instances marked as moved to alt storage */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen action = MDBOX_MSG_ACTION_MOVE_TO_ALT;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(ctx->altmoves,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(cur_map_uid),
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(action));
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&ctx->purge_file_ids,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen cur_rec.file_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* next add move-from-alt actions. they override move-to-alt actions
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen in case there happen to be any conflicts (shouldn't). only a single
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen move-from-alt record is needed to do the move. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (array_is_created(&dstorage->move_from_alt_map_uids))
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen map_uids = array_get(&dstorage->move_from_alt_map_uids, &count);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen map_uids = NULL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen count = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen cur_map_uid = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (i = 0; i < count; i++) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (cur_map_uid == map_uids[i])
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen continue;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen cur_map_uid = map_uids[i];
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_lookup(dstorage->map, cur_map_uid,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen &cur_rec.file_id, &offset) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen continue;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (seq_range_exists(&ctx->primary_file_ids, cur_rec.file_id)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* already in primary storage */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen continue;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen action = MDBOX_MSG_ACTION_MOVE_FROM_ALT;
c224fff79d18480a65e9b4504b891b8ea176f5b1Timo Sirainen hash_table_update(ctx->altmoves, POINTER_CAST(cur_map_uid),
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(action));
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&ctx->purge_file_ids, cur_rec.file_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->have_altmoves = hash_table_count(ctx->altmoves) > 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenint mdbox_purge(struct mail_storage *_storage)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *storage = (struct mdbox_storage *)_storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_purge_context *ctx;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct dbox_file *file;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct seq_range_iter iter;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int i = 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen uint32_t file_id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen bool deleted;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx = mdbox_purge_alloc(storage);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen ret = mdbox_map_get_zero_ref_files(storage->map, &ctx->purge_file_ids);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (storage->alt_storage_dir != NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (mdbox_purge_get_primary_files(ctx) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* add files that can be altmoved */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (mdbox_altmove_add_files(ctx) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen seq_range_array_iter_init(&iter, &ctx->purge_file_ids); i = 0;
b5c89a33fa14f3b8b19673c44eeecf1d131d690dTimo Sirainen while (ret == 0 &&
b5c89a33fa14f3b8b19673c44eeecf1d131d690dTimo Sirainen seq_range_array_iter_nth(&iter, i++, &file_id)) T_BEGIN {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen file = mdbox_file_init(storage, file_id);
4ca83616715c3bd417e34ced2c1d61852513e427Timo Sirainen if (dbox_file_open(file, &deleted) > 0 && !deleted) {
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen if (mdbox_file_purge(ctx, file, file_id) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } else {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mdbox_map_remove_file_id(storage->map, file_id) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_unref(&file);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } T_END;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mdbox_purge_free(&ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (storage->corrupted) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* purging found corrupted files */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (void)mdbox_storage_rebuild(storage);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}