bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen Altmoving works like:
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 /* 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 /* list of file_ids that we need to purge */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen /* uint32_t map_uid => enum mdbox_msg_action action */
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainenstatic int mdbox_map_file_msg_offset_cmp(const struct mdbox_map_file_msg *m1,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_file_read_metadata_hdr(struct dbox_file *file,
d868a04630bd7bfe9c1543a7c3f68703b3e276e4Timo Sirainen ret = i_stream_read_bytes(file->input, &data, &size,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file, "missing metadata");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(&file->storage->storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen memcpy(meta_hdr_r, data, sizeof(*meta_hdr_r));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (memcmp(meta_hdr_r->magic_post, DBOX_MAGIC_POST,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file, "invalid metadata magic");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_stream_skip(file->input, sizeof(*meta_hdr_r));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_file_metadata_copy(struct dbox_file *file, struct ostream *output)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((ret = mdbox_file_read_metadata_hdr(file, &meta_hdr)) <= 0)
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) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* end of metadata */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_stream_set_max_buffer_size(file->input, buf_size);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dbox_file_set_corrupted(file, "missing end-of-metadata line");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_metadata_get_extrefs(struct dbox_file *file, pool_t ext_refs_pool,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* skip and ignore the header */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((ret = mdbox_file_read_metadata_hdr(file, &meta_hdr)) <= 0)
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 /* end of metadata */
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (!index_attachment_parse_extrefs(line+1, ext_refs_pool,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("%s: Ignoring corrupted extref: %s",
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen i_stream_set_max_buffer_size(file->input, buf_size);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen dbox_file_set_corrupted(file, "missing end-of-metadata line");
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainenmdbox_purge_want_altpath(struct mdbox_purge_context *ctx,
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 Sirainenmdbox_purge_save_msg(struct mdbox_purge_context *ctx, struct dbox_file *file,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct dbox_file_append_context *out_file_append;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ctx->append_ctx = mdbox_map_append_begin(ctx->atomic);
8776322310b57a11c52cfb1822f35cf18b095525Timo Sirainen append_flags = !mdbox_purge_want_altpath(ctx, file, msg->map_uid) ? 0 :
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,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen input = i_stream_create_limit(file->input, msg_size);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(&file->storage->storage,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen "write(%s) failed: %s",
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen dbox_file_set_corrupted(file, "truncated message at EOF");
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen /* copy metadata */
f339a8e73beea7684ea634941ea82593dea522eeTimo Sirainen if ((ret = mdbox_file_metadata_copy(file, output)) <= 0)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainenmdbox_file_purge_check_refcounts(struct mdbox_purge_context *ctx,
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen const ARRAY_TYPE(mdbox_map_file_msg) *msgs_arr)
62958c5eefcd7dd84717b487ca36ec3a86949eb9Timo Sirainen if (mdbox_map_atomic_lock(ctx->atomic, "purging check") < 0)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen for (i = 0; i < count; i++) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen ret = mdbox_map_lookup_full(map, msgs[i].map_uid, &rec,
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen "Purging unexpectedly lost map_uid=%u",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmdbox_purge_attachments(struct mdbox_purge_context *ctx,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs_arr)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_storage *storage = &ctx->storage->storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (index_attachment_delete(&storage->storage,
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainenmdbox_file_purge(struct mdbox_purge_context *ctx, struct dbox_file *file,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *dstorage = (struct mdbox_storage *)file->storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* make sure the file still exists. another process may have already
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen deleted it. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen mail_storage_set_critical(&file->storage->storage,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* get list of map UIDs that exist in this file (again has to be done
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen after locking) */
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen if (mdbox_map_get_file_msgs(dstorage->map, file_id,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* sort messages by their offset */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_sort(&msgs_arr, mdbox_map_file_msg_offset_cmp);
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 i_array_init(&copied_map_uids, I_MIN(count, 1));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_array_init(&expunged_map_uids, I_MIN(count, 1));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (i = 0; i < count; i++) {
a81b240cfe84231eac64084efd5b0e1e91a9e817Timo Sirainen if ((ret = dbox_file_seek(file, offset)) <= 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* map doesn't match file's actual contents */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "purging found mismatched offsets "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* skip over expunged message */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* skip metadata */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = mdbox_metadata_get_extrefs(file, ext_refs_pool,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* non-expunged message. write it to output file. */
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen ret = mdbox_purge_save_msg(ctx, file, &msgs[i]);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen array_append(&copied_map_uids, &msgs[i].map_uid, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (offset != (uoff_t)st.st_size && ret > 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* file has more messages than what map tells us */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "more messages available than in map "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "(%"PRIuUOFF_T" < %"PRIuUOFF_T")", offset, st.st_size);
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen /* flush writes before locking the map */
cc4bac5d314d4801fa9759704a29393da8f29399Timo Sirainen if (mdbox_map_append_flush(ctx->append_ctx) < 0)
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 ret = mdbox_file_purge_check_refcounts(ctx, &msgs_arr);
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen /* everything purged from this file */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* assign new file_id + offset to moved messages */
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_append_move(ctx->append_ctx, &copied_map_uids,
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* unlink only after unlocking map, so readers don't see it
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen temporarily vanished */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mdbox_map_remove_file_id(ctx->storage->map, file_id) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (void)mdbox_purge_attachments(ctx, &ext_refs);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenvoid mdbox_purge_alt_flag_change(struct mail *mail, bool move_to_alt)
b67974c4b89ab6950c2694cce8dfb1b6561cc084Josef 'Jeff' Sipek struct mdbox_mailbox *mbox = MDBOX_MAILBOX(mail->box);
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 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 dest = move_to_alt ? &mbox->storage->move_to_alt_map_uids :
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenmdbox_purge_alloc(struct mdbox_storage *storage)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen pool = pool_alloconly_create("mdbox purge context", 1024*32);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx = p_new(pool, struct mdbox_purge_context, 1);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&ctx->altmoves, pool, 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void mdbox_purge_free(struct mdbox_purge_context **_ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int mdbox_purge_get_primary_files(struct mdbox_purge_context *ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *dstorage = ctx->storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mail_storage *storage = &dstorage->storage.storage;
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 /* no storage directory at all yet */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "opendir(%s) failed: %m", dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (errno = 0; (d = readdir(dir)) != NULL; errno = 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strncmp(d->d_name, MDBOX_MAIL_FILE_PREFIX,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (str_to_uint32(d->d_name + strlen(MDBOX_MAIL_FILE_PREFIX),
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&ctx->primary_file_ids, file_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (array_count(&ctx->primary_file_ids) > 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "readdir(%s) failed: %m", dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "closedir(%s) failed: %m", dstorage->storage_dir);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int uint32_t_cmp(const uint32_t *u1, const uint32_t *u2)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int mdbox_altmove_add_files(struct mdbox_purge_context *ctx)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *dstorage = ctx->storage;
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 for (i = 0; i < count; i++) {
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_lookup_full(dstorage->map, cur_map_uid,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen seq_range_exists(&ctx->primary_file_ids, cur_rec.file_id)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* all instances marked as moved to alt storage */
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 for (i = 0; i < count; i++) {
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (mdbox_map_lookup(dstorage->map, cur_map_uid,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (seq_range_exists(&ctx->primary_file_ids, cur_rec.file_id)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* already in primary storage */
c224fff79d18480a65e9b4504b891b8ea176f5b1Timo Sirainen hash_table_update(ctx->altmoves, POINTER_CAST(cur_map_uid),
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&ctx->purge_file_ids, cur_rec.file_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->have_altmoves = hash_table_count(ctx->altmoves) > 0;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct mdbox_storage *storage = (struct mdbox_storage *)_storage;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int i = 0;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen ret = mdbox_map_get_zero_ref_files(storage->map, &ctx->purge_file_ids);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* add files that can be altmoved */
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 {
4ca83616715c3bd417e34ced2c1d61852513e427Timo Sirainen if (dbox_file_open(file, &deleted) > 0 && !deleted) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mdbox_map_remove_file_id(storage->map, file_id) < 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* purging found corrupted files */