changeset 14674:efd276ab2577

Merged changes from v2.1 tree.
author Timo Sirainen <tss@iki.fi>
date Sun, 24 Jun 2012 20:57:06 +0300
parents a77ad2346cf0 (current diff) c257b9c19915 (diff)
children f07ba5e7d97d
files configure.in src/auth/auth-request.c src/auth/db-ldap.c src/director/director-connection.c src/doveadm/doveadm-log.c src/lib-index/mail-transaction-log-file.c src/lib-mail/message-parser.c src/lib-master/master-instance.c src/lib-master/master-service.c src/lib-storage/index/dbox-multi/mdbox-map.c src/lib-storage/index/imapc/imapc-mailbox.c src/lib-storage/index/imapc/imapc-storage.c src/lib-storage/index/mbox/mbox-mail.c src/lib-storage/index/shared/shared-list.c src/lib-storage/list/mailbox-list-index-status.c src/plugins/quota/quota-maildir.c src/plugins/quota/quota.c
diffstat 44 files changed, 337 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Sun Jun 24 20:48:38 2012 +0300
+++ b/.hgsigs	Sun Jun 24 20:57:06 2012 +0300
@@ -46,3 +46,4 @@
 2c21c940e19d97a772128a7f281cea302e157d73 0 iEYEABECAAYFAk+CtkYACgkQyUhSUUBVisknxgCfTJw2YPGJ17HbHRGmbwmCyLqepbMAn17j7IYzUfEU0xkXhCgwEAmk7XO4
 469cee314d9c54d2d7101ec9e38579fdc9610eaf 0 iEYEABECAAYFAk+VWqkACgkQyUhSUUBVislnXACfVjPqMmPUvYtXQXwqff0h7N76mZUAn02lPeUCyuyr1TF9e1hGM/sKgmko
 7c249e2a82a9cd33ae15ead6443c3499e16da623 0 iEYEABECAAYFAk+nX2sACgkQyUhSUUBVisn7uwCbBD3boxBOGEJ8OYsIJ57n5Cr09FAAoIvhxL6EHRB15AMOw4sPaALJ3/bB
+c92fb8b928f69ca01681a2c2976304b7e4bc3afc 0 iEYEABECAAYFAk/FIeIACgkQyUhSUUBVisk4IgCfUiXVXntqzPjJcALYRpqw4Zc7a/0An3HKWwgb6PBCbmvxBfTezNkqjqVK
--- a/.hgtags	Sun Jun 24 20:48:38 2012 +0300
+++ b/.hgtags	Sun Jun 24 20:57:06 2012 +0300
@@ -83,3 +83,4 @@
 2c21c940e19d97a772128a7f281cea302e157d73 2.1.4
 469cee314d9c54d2d7101ec9e38579fdc9610eaf 2.1.5
 7c249e2a82a9cd33ae15ead6443c3499e16da623 2.1.6
+c92fb8b928f69ca01681a2c2976304b7e4bc3afc 2.1.7
--- a/NEWS	Sun Jun 24 20:48:38 2012 +0300
+++ b/NEWS	Sun Jun 24 20:57:06 2012 +0300
@@ -1,3 +1,22 @@
+v2.1.7 2012-05-29  Timo Sirainen <tss@iki.fi>
+
+	* LDAP: Compatibility fix for v2.0: ldap: If attributes contain
+	  ldapAttr=key=template%$ and ldapAttr doesn't exist, skip the key
+	  instead of using "template" value with empty %$ part for the key.
+
+	+ pop3: Added pop3_uidl_duplicates setting for changing the behavior
+	  for duplicate UIDLs.
+	+ director: Added "doveadm director ring remove" command.
+	- director: Don't crash with quickly disconnecting incoming director
+	  connections.
+	- mdbox: If mail was originally saved to non-INBOX, and namespace
+	  prefix is non-empty, don't assert-crash when rebuilding indexes.
+	- sdbox: Don't use more fds than necessary when copying mails.
+	- auth: Fixed crash with DIGEST-MD5 when attempting to do master user
+	  login without master passdbs. 
+	- Several fixes to mail_shared_explicit_inbox=no
+	- imapc: Use imapc_list_prefix also for listing subscriptions.
+
 v2.1.6 2012-05-07  Timo Sirainen <tss@iki.fi>
 
 	* Session ID is now included by default in auth and login process
--- a/doc/example-config/conf.d/20-imap.conf	Sun Jun 24 20:48:38 2012 +0300
+++ b/doc/example-config/conf.d/20-imap.conf	Sun Jun 24 20:57:06 2012 +0300
@@ -18,7 +18,7 @@
   # IMAP logout format string:
   #  %i - total number of bytes read from client
   #  %o - total number of bytes sent to client
-  #imap_logout_format = bytes=%i/%o
+  #imap_logout_format = in=%i out=%o
 
   # Override the IMAP CAPABILITY response. If the value begins with '+',
   # add the given capabilities on top of the defaults (e.g. +XFOO XBAR).
--- a/src/auth/auth-request.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/auth/auth-request.c	Sun Jun 24 20:57:06 2012 +0300
@@ -1258,6 +1258,8 @@
 	i_assert(*name != '\0');
 	i_assert(value != NULL);
 
+	i_assert(request->passdb != NULL);
+
 	if (strcmp(name, "password") == 0) {
 		auth_request_set_password(request, value,
 					  default_scheme, FALSE);
--- a/src/auth/db-ldap.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/auth/db-ldap.c	Sun Jun 24 20:57:06 2012 +0300
@@ -866,6 +866,7 @@
 		ret = ldap_start_tls_s(conn->ld, NULL, NULL);
 		if (ret != LDAP_SUCCESS) {
 			if (ret == LDAP_OPERATIONS_ERROR &&
+			    conn->set.uris != NULL &&
 			    strncmp(conn->set.uris, "ldaps:", 6) == 0) {
 				i_fatal("LDAP: Don't use both tls=yes "
 					"and ldaps URI");
--- a/src/auth/password-scheme.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/auth/password-scheme.c	Sun Jun 24 20:57:06 2012 +0300
@@ -367,7 +367,7 @@
 		str = password_generate_md5_crypt(plaintext, password);
 		return strcmp(str, password) == 0 ? 1 : 0;
 	} else if (password_decode(password, "PLAIN-MD5",
-				   &md5_password, &md5_size, &error) < 0) {
+				   &md5_password, &md5_size, &error) <= 0) {
 		*error_r = "Not a valid MD5-CRYPT or PLAIN-MD5 password";
 		return -1;
 	} else {
--- a/src/director/director-connection.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/director/director-connection.c	Sun Jun 24 20:57:06 2012 +0300
@@ -711,7 +711,7 @@
 	bool weak = TRUE;
 	int ret;
 
-	if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) < 0)
+	if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
 		return FALSE;
 
 	if (str_array_length(args) != 2 ||
--- a/src/director/director.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/director/director.c	Sun Jun 24 20:57:06 2012 +0300
@@ -363,6 +363,11 @@
 {
 	/* we're synced again when we receive this SYNC back */
 	dir->sync_seq++;
+	if (dir->right == NULL && dir->left == NULL) {
+		/* we're alone. if we're already synced,
+		   don't become unsynced. */
+		return;
+	}
 	director_set_ring_unsynced(dir);
 
 	if (dir->sync_frozen) {
--- a/src/director/mail-host.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/director/mail-host.c	Sun Jun 24 20:57:06 2012 +0300
@@ -110,7 +110,7 @@
 	i2 = htonl(ip2_arr[i]);
 
 	for (j = last_bits; j < 32; j++) {
-		if ((i1 & (1 << j)) != (i2 & (1 << j))) {
+		if ((i1 & (1U << j)) != (i2 & (1U << j))) {
 			i_error("IP address range too large: %s-%s",
 				net_ip2addr(&ip1), net_ip2addr(&ip2));
 			return -1;
--- a/src/doveadm/doveadm-instance.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/doveadm/doveadm-instance.c	Sun Jun 24 20:57:06 2012 +0300
@@ -5,6 +5,7 @@
 #include "doveadm.h"
 #include "doveadm-print.h"
 
+#include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -42,22 +43,45 @@
 	return found;
 }
 
-static void cmd_instance_list(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
+static void cmd_instance_list(int argc, char *argv[])
 {
 	struct master_instance_list *list;
 	struct master_instance_list_iter *iter;
 	const struct master_instance *inst;
 	const char *pidfile_path;
+	bool show_config = FALSE;
+	int c;
 
-	doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
-	doveadm_print_header("path", "path", DOVEADM_PRINT_HEADER_FLAG_EXPAND);
-	doveadm_print_header_simple("name");
-	doveadm_print_header_simple("last used");
-	doveadm_print_header_simple("running");
+	while ((c = getopt(argc, argv, "c")) > 0) {
+		switch (c) {
+		case 'c':
+			show_config = TRUE;
+			break;
+		default:
+			help(&doveadm_cmd_instance[0]);
+		}
+	}
+	argv += optind;
+
+	if (!show_config) {
+		doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
+		doveadm_print_header("path", "path", DOVEADM_PRINT_HEADER_FLAG_EXPAND);
+		doveadm_print_header_simple("name");
+		doveadm_print_header_simple("last used");
+		doveadm_print_header_simple("running");
+	}
 
 	list = master_instance_list_init(MASTER_INSTANCE_PATH);
 	iter = master_instance_list_iterate_init(list);
 	while ((inst = master_instance_iterate_list_next(iter)) != NULL) {
+		if (argv[0] != NULL && strcmp(argv[0], inst->name) != 0)
+			continue;
+
+		if (show_config) {
+			printf("%s\n", inst->config_path == NULL ? "" :
+			       inst->config_path);
+			continue;
+		}
 		doveadm_print(inst->base_dir);
 		doveadm_print(inst->name);
 		doveadm_print(unixdate2str(inst->last_used));
@@ -95,7 +119,7 @@
 }
 
 struct doveadm_cmd doveadm_cmd_instance[] = {
-	{ cmd_instance_list, "instance list", "" },
+	{ cmd_instance_list, "instance list", "[-c] [<name>]" },
 	{ cmd_instance_remove, "instance remove", "<name> | <base dir>" }
 };
 
--- a/src/doveadm/doveadm-log.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/doveadm/doveadm-log.c	Sun Jun 24 20:57:06 2012 +0300
@@ -23,6 +23,8 @@
 #define LOG_ERRORS_FNAME "log-errors"
 #define LOG_TIMESTAMP_FORMAT "%b %d %H:%M:%S"
 
+extern struct doveadm_cmd doveadm_cmd_log[];
+
 static void ATTR_NULL(2)
 cmd_log_test(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
 {
@@ -279,7 +281,7 @@
 	}
 }
 
-static void cmd_log_error_write(const char *const *args)
+static void cmd_log_error_write(const char *const *args, time_t min_timestamp)
 {
 	/* <type> <timestamp> <prefix> <text> */
 	const char *type_prefix = "?";
@@ -298,16 +300,32 @@
 		i_error("Invalid timestamp: %s", args[1]);
 		t = 0;
 	}
-
-	printf("%s %s%s%s\n", t_strflocaltime(LOG_TIMESTAMP_FORMAT, t),
-	       args[2], type_prefix, args[3]);
+	if (t >= min_timestamp) {
+		printf("%s %s%s%s\n", t_strflocaltime(LOG_TIMESTAMP_FORMAT, t),
+		       args[2], type_prefix, args[3]);
+	}
 }
 
-static void cmd_log_errors(int argc ATTR_UNUSED, char *argv[] ATTR_UNUSED)
+static void cmd_log_errors(int argc, char *argv[])
 {
 	struct istream *input;
 	const char *path, *line, *const *args;
-	int fd;
+	time_t min_timestamp = 0;
+	int c, fd;
+
+	while ((c = getopt(argc, argv, "s:")) > 0) {
+		switch (c) {
+		case 's':
+			if (str_to_time(optarg, &min_timestamp) < 0)
+				i_fatal("Invalid timestamp: %s", optarg);
+			break;
+		default:
+			help(&doveadm_cmd_log[3]);
+		}
+	}
+	argv += optind - 1;
+	if (argv[1] != NULL)
+		help(&doveadm_cmd_log[3]);
 
 	path = t_strconcat(doveadm_settings->base_dir,
 			   "/"LOG_ERRORS_FNAME, NULL);
@@ -320,7 +338,7 @@
 	while ((line = i_stream_read_next_line(input)) != NULL) T_BEGIN {
 		args = t_strsplit_tabescaped(line);
 		if (str_array_length(args) == 4)
-			cmd_log_error_write(args);
+			cmd_log_error_write(args, min_timestamp);
 		else {
 			i_error("Invalid input from log: %s", line);
 			doveadm_exit_code = EX_PROTOCOL;
@@ -333,7 +351,7 @@
 	{ cmd_log_test, "log test", "" },
 	{ cmd_log_reopen, "log reopen", "" },
 	{ cmd_log_find, "log find", "[<dir>]" },
-	{ cmd_log_errors, "log errors", "" }
+	{ cmd_log_errors, "log errors", "[-s <min_timestamp>]" }
 };
 
 void doveadm_register_log_commands(void)
--- a/src/doveadm/doveadm-print.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/doveadm/doveadm-print.c	Sun Jun 24 20:57:06 2012 +0300
@@ -18,6 +18,7 @@
 	const struct doveadm_print_vfuncs *v;
 
 	unsigned int header_idx;
+	bool print_stream_open;
 };
 
 static struct doveadm_print_context *ctx;
@@ -52,7 +53,7 @@
 	doveadm_print_header(key_title, key_title, 0);
 }
 
-void doveadm_print(const char *value)
+static void doveadm_print_sticky_headers(void)
 {
 	const struct doveadm_print_header_context *headers;
 	unsigned int count;
@@ -68,7 +69,13 @@
 			break;
 		}
 	}
+}
 
+void doveadm_print(const char *value)
+{
+	i_assert(!ctx->print_stream_open);
+
+	doveadm_print_sticky_headers();
 	ctx->v->print(value);
 	ctx->header_idx++;
 }
@@ -82,9 +89,15 @@
 
 void doveadm_print_stream(const void *value, size_t size)
 {
+	if (!ctx->print_stream_open) {
+		doveadm_print_sticky_headers();
+		ctx->print_stream_open = TRUE;
+	}
 	ctx->v->print_stream(value, size);
-	if (size == 0)
+	if (size == 0) {
 		ctx->header_idx++;
+		ctx->print_stream_open = FALSE;
+	}
 }
 
 void doveadm_print_sticky(const char *key, const char *value)
--- a/src/doveadm/doveadm.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/doveadm/doveadm.c	Sun Jun 24 20:57:06 2012 +0300
@@ -5,7 +5,7 @@
 #include "str.h"
 #include "env-util.h"
 #include "execv-const.h"
-#include "master-service.h"
+#include "master-service-private.h"
 #include "master-service-settings.h"
 #include "settings-parser.h"
 #include "doveadm-print-private.h"
@@ -163,6 +163,8 @@
 
 static void cmd_config(int argc ATTR_UNUSED, char *argv[])
 {
+	env_put(t_strconcat(MASTER_CONFIG_FILE_ENV"=",
+		master_service_get_config_path(master_service), NULL));
 	argv[0] = BINDIR"/doveconf";
 	(void)execv(argv[0], argv);
 	i_fatal("execv(%s) failed: %m", argv[0]);
--- a/src/imap/cmd-delete.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/imap/cmd-delete.c	Sun Jun 24 20:57:06 2012 +0300
@@ -8,7 +8,8 @@
 	struct client *client = cmd->client;
 	struct mail_namespace *ns;
 	struct mailbox *box;
-	const char *name;
+	const char *name, *errstr;
+	enum mail_error error;
 
 	/* <mailbox> */
 	if (!client_read_string_args(cmd, 1, &name))
@@ -32,10 +33,17 @@
 		mailbox_free(&client->mailbox);
 	}
 
-	if (mailbox_delete(box) < 0)
-		client_send_storage_error(cmd, mailbox_get_storage(box));
-	else
+	if (mailbox_delete(box) == 0)
 		client_send_tagline(cmd, "OK Delete completed.");
+	else {
+		errstr = mailbox_get_last_error(box, &error);
+		if (error != MAIL_ERROR_EXISTS)
+			client_send_storage_error(cmd, mailbox_get_storage(box));
+		else {
+			/* mailbox has children */
+			client_send_tagline(cmd, t_strdup_printf("NO %s", errstr));
+		}
+	}
 	mailbox_free(&box);
 	return TRUE;
 }
--- a/src/lib-charset/charset-iconv.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-charset/charset-iconv.c	Sun Jun 24 20:57:06 2012 +0300
@@ -53,6 +53,20 @@
 		(void)iconv(t->cd, NULL, NULL, NULL, NULL);
 }
 
+static int
+charset_append_utf8(const void *src, size_t src_size,
+		    buffer_t *dest, bool dtcase)
+{
+	if (dtcase)
+		return uni_utf8_to_decomposed_titlecase(src, src_size, dest);
+	if (!uni_utf8_get_valid_data(src, src_size, dest))
+		return -1;
+	else {
+		buffer_append(dest, src, src_size);
+		return 0;
+	}
+}
+
 static bool
 charset_to_utf8_try(struct charset_translation *t,
 		    const unsigned char *src, size_t *src_size, buffer_t *dest,
@@ -65,30 +79,15 @@
 	bool ret = TRUE;
 
 	if (t->cd == (iconv_t)-1) {
-		/* no translation needed - just copy it to outbuf uppercased */
-		*result = CHARSET_RET_OK;
-		if (!dtcase) {
-			buffer_append(dest, src, *src_size);
-			return TRUE;
-		}
-
-		if (uni_utf8_to_decomposed_titlecase(src, *src_size, dest) < 0)
+		/* input is already supposed to be UTF-8 */
+		if (charset_append_utf8(src, *src_size, dest, dtcase) < 0)
 			*result = CHARSET_RET_INVALID_INPUT;
+		else
+			*result = CHARSET_RET_OK;
 		return TRUE;
 	}
-	if (!dtcase) {
-		destleft = buffer_get_size(dest) - dest->used;
-		if (destleft < *src_size) {
-			/* The buffer is most likely too small to hold the
-			   output, so increase it at least to the input size. */
-			destleft = *src_size;
-		}
-		ic_destbuf = buffer_append_space_unsafe(dest, destleft);
-	} else {
-		destleft = sizeof(tmpbuf);
-		ic_destbuf = tmpbuf;
-	}
-
+	destleft = sizeof(tmpbuf);
+	ic_destbuf = tmpbuf;
 	srcleft = *src_size;
 	ic_srcbuf = (ICONV_CONST char *) src;
 
@@ -108,17 +107,12 @@
 	}
 	*src_size -= srcleft;
 
-	if (!dtcase) {
-		/* give back the memory we didn't use */
-		buffer_set_used_size(dest, dest->used - destleft);
-	} else {
-		size_t tmpsize = sizeof(tmpbuf) - destleft;
-
-		/* we just converted data to UTF-8. it shouldn't be invalid,
-		   but Solaris iconv appears to pass invalid data through
-		   sometimes (e.g. 8 bit characters with UTF-7) */
-		(void)uni_utf8_to_decomposed_titlecase(tmpbuf, tmpsize, dest);
-	}
+	/* we just converted data to UTF-8. it shouldn't be invalid, but
+	   Solaris iconv appears to pass invalid data through sometimes
+	   (e.g. 8 bit characters with UTF-7) */
+	if (charset_append_utf8(tmpbuf, sizeof(tmpbuf) - destleft,
+				dest, dtcase) < 0)
+		*result = CHARSET_RET_INVALID_INPUT;
 	return ret;
 }
 
--- a/src/lib-dict/dict-file.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-dict/dict-file.c	Sun Jun 24 20:57:06 2012 +0300
@@ -492,7 +492,7 @@
 	/* refresh once more now that we're locked */
 	if (file_dict_refresh(dict) < 0) {
 		if (dotlock != NULL)
-			file_dotlock_delete(&dotlock);
+			(void)file_dotlock_delete(&dotlock);
 		else {
 			(void)close(fd);
 			file_unlock(&lock);
@@ -512,12 +512,20 @@
 	o_stream_cork(output);
 	iter = hash_table_iterate_init(dict->hash);
 	while (hash_table_iterate(iter, &key, &value)) {
-		o_stream_send_str(output, key);
-		o_stream_send(output, "\n", 1);
-		o_stream_send_str(output, value);
-		o_stream_send(output, "\n", 1);
+		(void)o_stream_send_str(output, key);
+		(void)o_stream_send(output, "\n", 1);
+		(void)o_stream_send_str(output, value);
+		(void)o_stream_send(output, "\n", 1);
 	}
+	o_stream_uncork(output);
 	hash_table_iterate_deinit(&iter);
+
+	if (output->stream_errno != 0) {
+		i_error("write(%s) failed: %m", temp_path);
+		o_stream_destroy(&output);
+		(void)close(fd);
+		return -1;
+	}
 	o_stream_destroy(&output);
 
 	if (dotlock != NULL) {
--- a/src/lib-index/mail-transaction-log-file.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-index/mail-transaction-log-file.c	Sun Jun 24 20:57:06 2012 +0300
@@ -1673,6 +1673,7 @@
 				file->filepath);
 			return 0;
 		}
+		i_assert(file->buffer != NULL);
 		return log_file_map_check_offsets(file, start_offset,
 						  end_offset);
 	}
@@ -1695,9 +1696,11 @@
 
 	i_assert(file->buffer == NULL || file->mmap_base != NULL ||
 		 file->sync_offset >= file->buffer_offset + file->buffer->used);
+	if (ret <= 0)
+		return ret;
 
-	return ret <= 0 ? ret :
-		log_file_map_check_offsets(file, start_offset, end_offset);
+	i_assert(file->buffer != NULL);
+	return log_file_map_check_offsets(file, start_offset, end_offset);
 }
 
 void mail_transaction_log_file_move_to_memory(struct mail_transaction_log_file
--- a/src/lib-index/mail-transaction-log.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-index/mail-transaction-log.c	Sun Jun 24 20:57:06 2012 +0300
@@ -463,6 +463,7 @@
 		/* try again */
 	}
 
+	i_assert(ret < 0 || log->head != NULL);
 	return ret;
 }
 
--- a/src/lib-master/master-instance.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-master/master-instance.c	Sun Jun 24 20:57:06 2012 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "abspath.h"
 #include "array.h"
 #include "istream.h"
 #include "ostream.h"
@@ -17,6 +18,9 @@
 	const char *path;
 
 	ARRAY_DEFINE(instances, struct master_instance);
+
+	unsigned int locked:1;
+	unsigned int config_paths_changed:1;
 };
 
 struct master_instance_list_iter {
@@ -50,6 +54,22 @@
 	pool_unref(&list->pool);
 }
 
+static void
+master_instance_update_config_path(struct master_instance_list *list,
+				   struct master_instance *inst)
+{
+	const char *path, *config_path;
+
+	/* update instance's config path if it has changed */
+	path = t_strconcat(inst->base_dir, "/"PACKAGE".conf", NULL);
+	if (t_readlink(path, &config_path) == 0) {
+		if (null_strcmp(inst->config_path, config_path) != 0) {
+			inst->config_path = p_strdup(list->pool, config_path);
+			list->config_paths_changed = TRUE;
+		}
+	}
+}
+
 static int
 master_instance_list_add_line(struct master_instance_list *list,
 			      const char *line)
@@ -58,9 +78,9 @@
 	const char *const *args;
 	time_t last_used;
 
-	/* <last used> <name> <base dir> */
+	/* <last used> <name> <base dir> [<config path>] */
 	args = t_strsplit_tabescaped(line);
-	if (str_array_length(args) != 3)
+	if (str_array_length(args) < 3)
 		return -1;
 	if (str_to_time(args[0], &last_used) < 0)
 		return -1;
@@ -69,6 +89,8 @@
 	inst->last_used = last_used;
 	inst->name = p_strdup(list->pool, args[1]);
 	inst->base_dir = p_strdup(list->pool, args[2]);
+	inst->config_path = p_strdup_empty(list->pool, args[3]);
+	master_instance_update_config_path(list, inst);
 	return 0;
 }
 
@@ -117,6 +139,9 @@
 		str_tabescape_write(str, inst->name);
 		str_append_c(str, '\t');
 		str_tabescape_write(str, inst->base_dir);
+		str_append_c(str, '\t');
+		if (inst->config_path != NULL)
+			str_tabescape_write(str, inst->config_path);
 		str_append_c(str, '\n');
 		(void)o_stream_send(output, str_data(str), str_len(str));
 	}
@@ -135,6 +160,8 @@
 {
 	int fd;
 
+	i_assert(!list->locked);
+
 	*dotlock_r = NULL;
 
 	fd = file_dotlock_open_mode(&dotlock_set, list->path, 0, 0644,
@@ -147,6 +174,7 @@
 		file_dotlock_delete(dotlock_r);
 		return -1;
 	}
+	list->locked = TRUE;
 	return fd;
 }
 
@@ -156,9 +184,13 @@
 	const char *lock_path = file_dotlock_get_lock_path(*dotlock);
 	int ret;
 
+	i_assert(list->locked);
+
 	T_BEGIN {
 		ret = master_instance_list_write(list, fd, lock_path);
 	} T_END;
+
+	list->locked = FALSE;
 	if (ret < 0) {
 		file_dotlock_delete(dotlock);
 		return -1;
@@ -168,6 +200,7 @@
 		file_dotlock_delete(dotlock);
 		return -1;
 	}
+	list->config_paths_changed = FALSE;
 	return file_dotlock_replace(dotlock, 0);
 }
 
@@ -201,6 +234,7 @@
 		inst->base_dir = p_strdup(list->pool, base_dir);
 	}
 	inst->last_used = time(NULL);
+	master_instance_update_config_path(list, inst);
 
 	return master_instance_write_finish(list, fd, &dotlock);
 }
@@ -223,6 +257,7 @@
 	    strcmp(orig_inst->base_dir, base_dir) != 0) {
 		/* name already used */
 		file_dotlock_delete(&dotlock);
+		list->locked = FALSE;
 		return 0;
 	}
 
@@ -258,11 +293,30 @@
 
 	if (i == count) {
 		file_dotlock_delete(&dotlock);
+		list->locked = FALSE;
 		return 0;
 	}
 	return master_instance_write_finish(list, fd, &dotlock) < 0 ? -1 : 1;
 }
 
+static int
+master_instance_list_refresh_and_update(struct master_instance_list *list)
+{
+	struct dotlock *dotlock;
+	int fd;
+
+	if (master_instance_list_refresh(list) < 0)
+		return -1;
+	if (list->config_paths_changed && !list->locked) {
+		/* write new config paths */
+		if ((fd = master_instance_write_init(list, &dotlock)) == -1)
+			return -1;
+		if (master_instance_write_finish(list, fd, &dotlock) < 0)
+			return -1;
+	}
+	return 0;
+}
+
 const struct master_instance *
 master_instance_list_find_by_name(struct master_instance_list *list,
 				  const char *name)
@@ -272,7 +326,7 @@
 	i_assert(*name != '\0');
 
 	if (array_count(&list->instances) == 0)
-		(void)master_instance_list_refresh(list);
+		(void)master_instance_list_refresh_and_update(list);
 
 	array_foreach(&list->instances, inst) {
 		if (strcmp(inst->name, name) == 0)
@@ -288,7 +342,7 @@
 
 	iter = i_new(struct master_instance_list_iter, 1);
 	iter->list = list;
-	(void)master_instance_list_refresh(list);
+	(void)master_instance_list_refresh_and_update(list);
 	return iter;
 }
 
--- a/src/lib-master/master-instance.h	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-master/master-instance.h	Sun Jun 24 20:57:06 2012 +0300
@@ -9,6 +9,7 @@
 	time_t last_used;
 	const char *name;
 	const char *base_dir;
+	const char *config_path;
 };
 
 struct master_instance_list *master_instance_list_init(const char *path);
--- a/src/lib-master/master-service.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-master/master-service.c	Sun Jun 24 20:57:06 2012 +0300
@@ -359,7 +359,6 @@
 		if (!get_instance_config(arg, &path))
 			i_fatal("Unknown instance name: %s", arg);
 		service->config_path = i_strdup(path);
-		service->keep_environment = TRUE;
 		break;
 	case 'k':
 		service->keep_environment = TRUE;
--- a/src/lib-ssl-iostream/iostream-openssl.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-ssl-iostream/iostream-openssl.c	Sun Jun 24 20:57:06 2012 +0300
@@ -246,7 +246,7 @@
 	*_ssl_io = NULL;
 
 	i_assert(ssl_io->refcount > 0);
-	if (--ssl_io->refcount >= 0)
+	if (--ssl_io->refcount > 0)
 		return;
 
 	ssl_iostream_free(ssl_io);
@@ -388,7 +388,8 @@
 			return 0;
 		}
 		if (ssl_io->closed) {
-			errno = ssl_io->plain_stream_errno;
+			errno = ssl_io->plain_stream_errno != 0 ?
+				ssl_io->plain_stream_errno : EPIPE;
 			return -1;
 		}
 		return 1;
@@ -396,7 +397,8 @@
 		ssl_io->want_read = TRUE;
 		(void)ssl_iostream_bio_sync(ssl_io);
 		if (ssl_io->closed) {
-			errno = ssl_io->plain_stream_errno;
+			errno = ssl_io->plain_stream_errno != 0 ?
+				ssl_io->plain_stream_errno : EPIPE;
 			return -1;
 		}
 		return ssl_io->want_read ? 0 : 1;
@@ -406,6 +408,7 @@
 			errstr = ssl_iostream_error();
 			errno = EINVAL;
 		} else if (ret != 0) {
+			i_assert(errno != 0);
 			errstr = strerror(errno);
 		} else {
 			/* EOF. */
@@ -500,6 +503,7 @@
 	const char *dnsname;
 	bool dns_names = FALSE;
 	unsigned int i, count;
+	int ret;
 
 	cert = SSL_get_peer_certificate(ssl);
 	i_assert(cert != NULL);
@@ -517,14 +521,15 @@
 		}
 	}
 	sk_GENERAL_NAME_pop_free(gnames, GENERAL_NAME_free);
-	X509_free(cert);
 
 	/* verify against CommonName only when there wasn't any DNS
 	   SubjectAltNames */
 	if (dns_names)
-		return i < count ? 0 : -1;
-
-	return strcmp(get_cname(cert), verify_name) == 0 ? 0 : -1;
+		ret = i < count ? 0 : -1;
+	else
+		ret = strcmp(get_cname(cert), verify_name) == 0 ? 0 : -1;
+	X509_free(cert);
+	return ret;
 }
 
 int ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io,
--- a/src/lib-ssl-iostream/istream-openssl.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-ssl-iostream/istream-openssl.c	Sun Jun 24 20:57:06 2012 +0300
@@ -21,6 +21,7 @@
 {
 	struct ssl_istream *sstream = (struct ssl_istream *)stream;
 
+	i_free(sstream->istream.w_buffer);
 	ssl_iostream_unref(&sstream->ssl_io);
 }
 
@@ -38,6 +39,7 @@
 	if (ret <= 0) {
 		if (ret < 0) {
 			/* handshake failed */
+			i_assert(errno != 0);
 			stream->istream.stream_errno = errno;
 		}
 		return ret;
--- a/src/lib-ssl-iostream/ostream-openssl.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-ssl-iostream/ostream-openssl.c	Sun Jun 24 20:57:06 2012 +0300
@@ -24,7 +24,8 @@
 
 	sstream->ssl_io->ssl_output = NULL;
 	ssl_iostream_unref(&sstream->ssl_io);
-	i_free(sstream->buffer);
+	if (sstream->buffer != NULL)
+		buffer_free(&sstream->buffer);
 }
 
 static size_t
--- a/src/lib-storage/index/dbox-multi/mdbox-map-private.h	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-map-private.h	Sun Jun 24 20:57:06 2012 +0300
@@ -57,6 +57,7 @@
 	unsigned int map_refreshed:1;
 	unsigned int locked:1;
 	unsigned int success:1;
+	unsigned int failed:1;
 };
 
 int mdbox_map_view_lookup_rec(struct mdbox_map *map,
--- a/src/lib-storage/index/dbox-multi/mdbox-map.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-map.c	Sun Jun 24 20:57:06 2012 +0300
@@ -517,11 +517,13 @@
 void mdbox_map_atomic_set_failed(struct mdbox_map_atomic_context *atomic)
 {
 	atomic->success = FALSE;
+	atomic->failed = TRUE;
 }
 
 void mdbox_map_atomic_set_success(struct mdbox_map_atomic_context *atomic)
 {
-	atomic->success = TRUE;
+	if (!atomic->failed)
+		atomic->success = TRUE;
 }
 
 int mdbox_map_atomic_finish(struct mdbox_map_atomic_context **_atomic)
@@ -593,7 +595,7 @@
 		mail_index_reset_error(ctx->atomic->map->index);
 		return -1;
 	}
-	ctx->atomic->success = TRUE;
+	mdbox_map_atomic_set_success(ctx->atomic);
 	return 0;
 }
 
@@ -1365,6 +1367,21 @@
 	return 0;
 }
 
+int mdbox_map_append_flush(struct mdbox_map_append_context *ctx)
+{
+	struct dbox_file_append_context **file_appends;
+	unsigned int i, count;
+
+	i_assert(ctx->trans == NULL);
+
+	file_appends = array_get_modifiable(&ctx->file_appends, &count);
+	for (i = 0; i < count; i++) {
+		if (dbox_file_append_flush(file_appends[i]) < 0)
+			return -1;
+	}
+	return 0;
+}
+
 int mdbox_map_append_commit(struct mdbox_map_append_context *ctx)
 {
 	struct dbox_file_append_context **file_appends;
@@ -1377,7 +1394,7 @@
 		if (dbox_file_append_commit(&file_appends[i]) < 0)
 			return -1;
 	}
-	ctx->atomic->success = TRUE;
+	mdbox_map_atomic_set_success(ctx->atomic);
 	return 0;
 }
 
--- a/src/lib-storage/index/dbox-multi/mdbox-map.h	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-map.h	Sun Jun 24 20:57:06 2012 +0300
@@ -115,6 +115,8 @@
 int mdbox_map_append_move(struct mdbox_map_append_context *ctx,
 			  const ARRAY_TYPE(uint32_t) *map_uids,
 			  const ARRAY_TYPE(seq_range) *expunge_map_uids);
+/* Flush/fsync appends. */
+int mdbox_map_append_flush(struct mdbox_map_append_context *ctx);
 /* Returns 0 if ok, -1 if error. */
 int mdbox_map_append_commit(struct mdbox_map_append_context *ctx);
 void mdbox_map_append_free(struct mdbox_map_append_context **ctx);
--- a/src/lib-storage/index/dbox-multi/mdbox-save.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-save.c	Sun Jun 24 20:57:06 2012 +0300
@@ -287,6 +287,12 @@
 
 	i_assert(ctx->ctx.finished);
 
+	/* flush/fsync writes to m.* files before locking the map */
+	if (mdbox_map_append_flush(ctx->append_ctx) < 0) {
+		mdbox_transaction_save_rollback(_ctx);
+		return -1;
+	}
+
 	/* make sure the map gets locked */
 	if (mdbox_map_atomic_lock(ctx->atomic) < 0) {
 		mdbox_transaction_save_rollback(_ctx);
--- a/src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c	Sun Jun 24 20:57:06 2012 +0300
@@ -605,6 +605,7 @@
 	if (ret > 0 && !deleted && dbox_file_metadata_read(file) > 0) {
 		mailbox = dbox_file_metadata_get(file,
 						 DBOX_METADATA_ORIG_MAILBOX);
+		mailbox = mailbox_list_get_vname(ctx->default_list, mailbox);
 		mailbox = t_strdup(mailbox);
 	}
 	dbox_file_unref(&file);
@@ -623,7 +624,7 @@
 	   there. */
 	created = FALSE;
 	box = ctx->prev_msg.box != NULL &&
-		strcmp(mailbox, ctx->prev_msg.box->name) == 0 ?
+		strcmp(mailbox, ctx->prev_msg.box->vname) == 0 ?
 		ctx->prev_msg.box : NULL;
 	while (box == NULL) {
 		box = mailbox_alloc(ctx->default_list, mailbox,
--- a/src/lib-storage/index/imapc/imapc-mailbox.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/imapc/imapc-mailbox.c	Sun Jun 24 20:57:06 2012 +0300
@@ -338,7 +338,7 @@
 		mail_index_update_flags(mbox->delayed_sync_trans, lseq,
 					MODIFY_REPLACE, flags);
 	}
-	if (seen_flags) T_BEGIN {
+	if (seen_flags) {
 		ARRAY_TYPE(keyword_indexes) old_kws;
 		struct mail_keywords *kw;
 
@@ -354,7 +354,7 @@
 						   lseq, MODIFY_REPLACE, kw);
 		}
 		mail_index_keywords_unref(&kw);
-	} T_END;
+	}
 	imapc_mailbox_idle_notify(mbox);
 }
 
--- a/src/lib-storage/index/imapc/imapc-storage.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/imapc/imapc-storage.c	Sun Jun 24 20:57:06 2012 +0300
@@ -275,6 +275,19 @@
 	imapc_client_deinit(&storage->client);
 }
 
+static void imapc_storage_add_list(struct mail_storage *_storage,
+				   struct mailbox_list *_list)
+{
+	struct imapc_storage *storage = (struct imapc_storage *)_storage;
+	struct imapc_mailbox_list *list = (struct imapc_mailbox_list *)_list;
+
+	i_assert(storage->list != NULL);
+	i_assert(storage->list->sep != '\0');
+
+	list->storage = storage;
+	list->sep = storage->list->sep;
+}
+
 void imapc_storage_register_untagged(struct imapc_storage *storage,
 				     const char *name,
 				     imapc_storage_callback_t *callback)
@@ -753,7 +766,7 @@
 		imapc_storage_alloc,
 		imapc_storage_create,
 		imapc_storage_destroy,
-		NULL,
+		imapc_storage_add_list,
 		imapc_storage_get_list_settings,
 		NULL,
 		imapc_mailbox_alloc,
--- a/src/lib-storage/index/mbox/mbox-mail.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/mbox/mbox-mail.c	Sun Jun 24 20:57:06 2012 +0300
@@ -241,6 +241,8 @@
 	int trailer_size;
 	int ret = 1;
 
+	*next_offset_r = (uoff_t)-1;
+
 	hdr = mail_index_get_header(mail->mail.mail.transaction->view);
 	if (mail->mail.mail.seq > hdr->messages_count) {
 		/* we're appending a new message */
@@ -342,8 +344,6 @@
 				  mail->mail.mail.uid);
 		}
 	}
-	if (ret <= 0)
-		next_offset = (uoff_t)-1;
 
 	raw_stream = mbox->mbox_stream;
 	hdr_offset = istream_raw_mbox_get_header_offset(raw_stream);
--- a/src/lib-storage/index/mbox/mbox-save.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/mbox/mbox-save.c	Sun Jun 24 20:57:06 2012 +0300
@@ -666,6 +666,7 @@
 
 	ctx->finished = TRUE;
 	if (!ctx->failed) {
+		i_assert(ctx->output != NULL);
 		T_BEGIN {
 			if (mbox_write_content_length(ctx) < 0 ||
 			    mbox_append_lf(ctx) < 0)
--- a/src/lib-storage/index/shared/shared-list.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/index/shared/shared-list.c	Sun Jun 24 20:57:06 2012 +0300
@@ -43,8 +43,12 @@
 	const char *name;
 
 	name = mailbox_list_get_storage_name(*list, vname);
-	if (shared_storage_get_namespace(&ns, &name) < 0)
-		return -1;
+	if (*name == '\0' && (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+		/* trying to access the shared/ prefix itself */
+	} else {
+		if (shared_storage_get_namespace(&ns, &name) < 0)
+			return -1;
+	}
 	*list = ns->list;
 	*storage_r = ns->storage;
 	return 0;
--- a/src/lib-storage/mail-search-register-imap.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib-storage/mail-search-register-imap.c	Sun Jun 24 20:57:06 2012 +0300
@@ -259,6 +259,8 @@
 	/* <hdr-name> <string> */
 	if (mail_search_parse_string(ctx->parser, &hdr_name) < 0)
 		return NULL;
+	if (mail_search_build_get_utf8(ctx, hdr_name, &hdr_name) < 0)
+		return NULL;
 
 	return arg_new_header(ctx, SEARCH_HEADER, t_str_ucase(hdr_name));
 }
--- a/src/lib/primes.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib/primes.c	Sun Jun 24 20:57:06 2012 +0300
@@ -41,7 +41,7 @@
 	unsigned int i;
 
 	for (i = 31; i > PRIME_SKIP_COUNT; i--) {
-		if ((num & (1 << i)) != 0)
+		if ((num & (1U << i)) != 0)
 			return primes[i - PRIME_SKIP_COUNT];
 	}
 	return primes[0];
--- a/src/lib/restrict-access.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib/restrict-access.c	Sun Jun 24 20:57:06 2012 +0300
@@ -126,7 +126,7 @@
 		i_fatal("getgroups() failed: %m");
 
 	/* @UNSAFE */
-	gid_list = t_new(gid_t, gid_count);
+	gid_list = t_new(gid_t, gid_count+1); /* +1 in case gid_count=0 */
 	if ((ret = getgroups(gid_count, gid_list)) < 0)
 		i_fatal("getgroups() failed: %m");
 
--- a/src/lib/utc-mktime.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/lib/utc-mktime.c	Sun Jun 24 20:57:06 2012 +0300
@@ -33,7 +33,7 @@
 #ifdef TIME_T_SIGNED
 	t = 0;
 #else
-	t = 1 << (TIME_T_MAX_BITS - 1);
+	t = (time_t)1 << (TIME_T_MAX_BITS - 1);
 #endif
 	for (bits = TIME_T_MAX_BITS - 2;; bits--) {
 		try_tm = gmtime(&t);
--- a/src/master/service-monitor.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/master/service-monitor.c	Sun Jun 24 20:57:06 2012 +0300
@@ -237,19 +237,27 @@
 static void service_drop_connections(struct service_listener *l)
 {
 	struct service *service = l->service;
+	const char *limit_name;
 	unsigned int limit;
 	int fd;
 
 	if (service->last_drop_warning +
 	    SERVICE_DROP_WARN_INTERVAL_SECS < ioloop_time) {
 		service->last_drop_warning = ioloop_time;
-		limit = service->process_limit > 1 ?
-			service->process_limit : service->client_limit;
+		if (service->process_limit > 1) {
+			limit_name = "process_limit";
+			limit = service->process_limit;
+		} else if (service->set->service_count == 1) {
+			i_assert(service->client_limit == 1);
+			limit_name = "client_limit/service_count";
+			limit = 1;
+		} else {
+			limit_name = "client_limit";
+			limit = service->client_limit;
+		}
 		i_warning("service(%s): %s (%u) reached, "
 			  "client connections are being dropped",
-			  service->set->name,
-			  service->process_limit > 1 ?
-			  "process_limit" : "client_limit", limit);
+			  service->set->name, limit_name, limit);
 	}
 
 	if (service->type == SERVICE_TYPE_LOGIN) {
--- a/src/plugins/fts-squat/fts-backend-squat.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/plugins/fts-squat/fts-backend-squat.c	Sun Jun 24 20:57:06 2012 +0300
@@ -452,9 +452,10 @@
 				       &result->maybe_uids);
 		if (ret < 0)
 			return -1;
-		if (ret > 0)
+		if (ret > 0) {
 			args->match_always = TRUE;
-		first = FALSE;
+			first = FALSE;
+		}
 	}
 	return 0;
 }
--- a/src/plugins/fts-squat/squat-uidlist.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/plugins/fts-squat/squat-uidlist.c	Sun Jun 24 20:57:06 2012 +0300
@@ -1416,6 +1416,7 @@
 		squat_uidlist_set_corrupted(uidlist, "uidlist not found");
 		return -1;
 	}
+	i_assert(uidlist->cur_block_end_indexes != NULL);
 	if (unlikely(idx > 0 &&
 		     uidlist->cur_block_end_indexes[idx-1] > uid_list_idx)) {
 		squat_uidlist_set_corrupted(uidlist, "broken block list");
@@ -1430,6 +1431,7 @@
 		return -1;
 
 	/* find the uidlist inside the block */
+	i_assert(uidlist->cur_block_offsets != NULL);
 	p = CONST_PTR_OFFSET(uidlist->data, uidlist->cur_block_offsets[idx]);
 	end = CONST_PTR_OFFSET(uidlist->data, uidlist->data_size);
 
--- a/src/plugins/quota/quota-maildir.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/plugins/quota/quota-maildir.c	Sun Jun 24 20:57:06 2012 +0300
@@ -546,12 +546,15 @@
 		!CMP_DEV_T(st1.st_dev, st2.st_dev);
 }
 
-static int maildirsize_read(struct maildir_quota_root *root)
+static int maildirsize_read(struct maildir_quota_root *root, bool *retry)
 {
 	char buf[5120+1];
 	unsigned int i, size;
+	bool retry_estale = *retry;
 	int ret;
 
+	*retry = FALSE;
+
 	if (!maildirsize_has_changed(root))
 		return 1;
 
@@ -562,8 +565,10 @@
 	size = 0;
 	while ((ret = read(root->fd, buf + size, sizeof(buf)-1 - size)) != 0) {
 		if (ret < 0) {
-			if (errno == ESTALE)
+			if (errno == ESTALE && retry_estale) {
+				*retry = TRUE;
 				break;
+			}
 			i_error("read(%s) failed: %m", root->maildirsize_path);
 			break;
 		}
@@ -644,14 +649,20 @@
 
 static int maildirquota_read_limits(struct maildir_quota_root *root)
 {
-	int ret;
+	bool retry = TRUE;
+	int ret, n = 0;
 
 	if (!maildirquota_limits_init(root))
 		return 1;
 
-	T_BEGIN {
-		ret = maildirsize_read(root);
-	} T_END;
+	do {
+		if (n == NFS_ESTALE_RETRY_COUNT)
+			retry = FALSE;
+		T_BEGIN {
+			ret = maildirsize_read(root, &retry);
+		} T_END;
+		n++;
+	} while (ret == -1 && retry);
 	return ret;
 }
 
--- a/src/plugins/quota/quota.c	Sun Jun 24 20:48:38 2012 +0300
+++ b/src/plugins/quota/quota.c	Sun Jun 24 20:57:06 2012 +0300
@@ -638,7 +638,7 @@
 		for (i = 0; i < count; i++) {
 			path2 = mailbox_list_get_root_path(namespaces[i]->list,
 				     	MAILBOX_LIST_PATH_TYPE_MAILBOX);
-			if (strcmp(path, path2) == 0) {
+			if (path2 != NULL && strcmp(path, path2) == 0) {
 				/* duplicate */
 				return;
 			}