changeset 21601:15e700c083c0

lib-storage: Fix error handling when searching mails Only expunge errors and failures caused by lookup_abort should be ignored. The rest of the mail errors mean that the search result might not be correct. We'll still run the search as fully as possible, but we just return an error at the end.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 17 Feb 2017 18:30:51 +0200
parents 236081fab146
children 9aac2a64e5c2
files src/lib-storage/index/index-search.c
diffstat 1 files changed, 67 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/index-search.c	Fri Feb 17 18:24:31 2017 +0200
+++ b/src/lib-storage/index/index-search.c	Fri Feb 17 18:30:51 2017 +0200
@@ -66,6 +66,31 @@
 {
 }
 
+static void search_set_failed(struct index_search_context *ctx)
+{
+	if (ctx->failed)
+		return;
+
+	/* remember the first failure */
+	mail_storage_last_error_push(ctx->box->storage);
+	ctx->failed = TRUE;
+}
+
+static void search_cur_mail_failed(struct index_search_context *ctx)
+{
+	switch (mailbox_get_last_mail_error(ctx->cur_mail->box)) {
+	case MAIL_ERROR_EXPUNGED:
+		ctx->mail_ctx.seen_lost_data = TRUE;
+		break;
+	case MAIL_ERROR_NOTPOSSIBLE:
+		/* lookup_abort hit */
+		break;
+	default:
+		search_set_failed(ctx);
+		break;
+	}
+}
+
 static void search_init_arg(struct mail_search_arg *arg,
 			    struct index_search_context *ctx)
 {
@@ -255,8 +280,10 @@
 		if (strcmp(box->vname, arg->value.str) == 0)
 			return 1;
 		if (mail_get_special(ctx->cur_mail, MAIL_FETCH_MAILBOX_NAME,
-				     &str) < 0)
+				     &str) < 0) {
+			search_cur_mail_failed(ctx);
 			return -1;
+		}
 
 		if (strcasecmp(str, "INBOX") == 0)
 			return strcasecmp(arg->value.str, "INBOX") == 0;
@@ -265,8 +292,10 @@
 		if (imap_match(arg->initialized.mailbox_glob, box->vname) == IMAP_MATCH_YES)
 			return 1;
 		if (mail_get_special(ctx->cur_mail, MAIL_FETCH_MAILBOX_NAME,
-				     &str) < 0)
+				     &str) < 0) {
+			search_cur_mail_failed(ctx);
 			return -1;
+		}
 		return imap_match(arg->initialized.mailbox_glob, str) == IMAP_MATCH_YES;
 	default:
 		return -1;
@@ -308,17 +337,23 @@
 		have_tz_offset = FALSE; tz_offset = 0; date = (time_t)-1;
 		switch (arg->value.date_type) {
 		case MAIL_SEARCH_DATE_TYPE_SENT:
-			if (mail_get_date(ctx->cur_mail, &date, &tz_offset) < 0)
+			if (mail_get_date(ctx->cur_mail, &date, &tz_offset) < 0) {
+				search_cur_mail_failed(ctx);
 				return -1;
+			}
 			have_tz_offset = TRUE;
 			break;
 		case MAIL_SEARCH_DATE_TYPE_RECEIVED:
-			if (mail_get_received_date(ctx->cur_mail, &date) < 0)
+			if (mail_get_received_date(ctx->cur_mail, &date) < 0) {
+				search_cur_mail_failed(ctx);
 				return -1;
+			}
 			break;
 		case MAIL_SEARCH_DATE_TYPE_SAVED:
-			if (mail_get_save_date(ctx->cur_mail, &date) < 0)
+			if (mail_get_save_date(ctx->cur_mail, &date) < 0) {
+				search_cur_mail_failed(ctx);
 				return -1;
+			}
 			break;
 		}
 
@@ -347,8 +382,10 @@
 	/* sizes */
 	case SEARCH_SMALLER:
 	case SEARCH_LARGER:
-		if (mail_get_virtual_size(ctx->cur_mail, &virtual_size) < 0)
+		if (mail_get_virtual_size(ctx->cur_mail, &virtual_size) < 0) {
+			search_cur_mail_failed(ctx);
 			return -1;
+		}
 
 		if (arg->type == SEARCH_SMALLER)
 			return virtual_size < arg->value.size;
@@ -356,14 +393,18 @@
 			return virtual_size > arg->value.size;
 
 	case SEARCH_GUID:
-		if (mail_get_special(ctx->cur_mail, MAIL_FETCH_GUID, &str) < 0)
+		if (mail_get_special(ctx->cur_mail, MAIL_FETCH_GUID, &str) < 0) {
+			search_cur_mail_failed(ctx);
 			return -1;
+		}
 		return strcmp(str, arg->value.str) == 0;
 	case SEARCH_REAL_UID: {
 		struct mail *real_mail;
 
-		if (mail_get_backend_mail(ctx->cur_mail, &real_mail) < 0)
+		if (mail_get_backend_mail(ctx->cur_mail, &real_mail) < 0) {
+			search_cur_mail_failed(ctx);
 			return -1;
+		}
 		return seq_range_exists(&arg->value.seqset, real_mail->uid);
 	}
 	default:
@@ -688,8 +729,10 @@
 	hdr_ctx.index_ctx = ctx;
 	/* hdr_ctx.imail is different from imail for mails in
 	   virtual mailboxes */
-	if (mail_get_backend_mail(ctx->cur_mail, &real_mail) < 0)
+	if (mail_get_backend_mail(ctx->cur_mail, &real_mail) < 0) {
+		search_cur_mail_failed(ctx);
 		return -1;
+	}
 	hdr_ctx.imail = (struct index_mail *)real_mail;
 	hdr_ctx.custom_header = TRUE;
 	hdr_ctx.args = args;
@@ -703,9 +746,10 @@
 		i_assert(*headers != NULL);
 
 		if (mail_get_header_stream(ctx->cur_mail, headers_ctx,
-					   &input) < 0)
+					   &input) < 0) {
+			search_cur_mail_failed(ctx);
 			failed = TRUE;
-		else {
+		} else {
 			message_parse_header(input, NULL, hdr_parser_flags,
 					     search_header, &hdr_ctx);
 		}
@@ -715,9 +759,10 @@
 		ret = have_body ?
 			mail_get_stream_because(ctx->cur_mail, NULL, NULL, "search", &input) :
 			mail_get_hdr_stream_because(ctx->cur_mail, NULL, "search", &input);
-		if (ret < 0)
+		if (ret < 0) {
+			search_cur_mail_failed(ctx);
 			failed = TRUE;
-		else {
+		} else {
 			hdr_ctx.parse_headers =
 				index_mail_want_parse_headers(hdr_ctx.imail);
 			if (hdr_ctx.parse_headers) {
@@ -732,6 +777,7 @@
 					i_stream_get_name(input),
 					i_stream_get_error(input));
 				failed = TRUE;
+				search_set_failed(ctx);
 			}
 		}
 	}
@@ -766,8 +812,10 @@
 		/* we didn't search headers. */
 		struct message_size hdr_size;
 
-		if (mail_get_stream_because(ctx->cur_mail, &hdr_size, NULL, "search", &input) < 0)
+		if (mail_get_stream_because(ctx->cur_mail, &hdr_size, NULL, "search", &input) < 0) {
+			search_cur_mail_failed(ctx);
 			return -1;
+		}
 		i_stream_seek(input, hdr_size.physical_size);
 	}
 
@@ -1239,9 +1287,9 @@
 	mail_search_args_reset(ctx->mail_ctx.args->args, TRUE);
 	if (args->have_inthreads) {
 		if (mail_thread_init(t->box, NULL, &ctx->thread_ctx) < 0)
-			ctx->failed = TRUE;
+			search_set_failed(ctx);
 		if (search_build_inthreads(ctx, args->args) < 0)
-			ctx->failed = TRUE;
+			search_set_failed(ctx);
 	}
 
 	if (sort_program != NULL) {
@@ -1303,6 +1351,9 @@
 		imail->search_mail = FALSE;
 		mail_free(mailp);
 	}
+
+	if (ctx->failed)
+		mail_storage_last_error_pop(ctx->box->storage);
 	array_free(&ctx->mails);
 	i_free(ctx);
 	return ret;
@@ -1393,9 +1444,6 @@
 
 static void search_match_finish(struct index_search_context *ctx, int match)
 {
-	if (ctx->cur_mail->expunged)
-		ctx->mail_ctx.seen_lost_data = TRUE;
-
 	if (match == 0 &&
 	    search_has_static_nonmatches(ctx->mail_ctx.args->args)) {
 		/* if there are saved search results remember
@@ -1748,8 +1796,6 @@
 		   returning the messages. */
 		ctx->sorted = TRUE;
 		index_sort_list_finish(_ctx->sort_program);
-		if (ctx->failed)
-			return FALSE;
 	}
 
 	/* everything searched at this point already. just returning