changeset 50:d493b9cc265e HEAD

Introduced uoff_t which is the unsigned-equilevant of off_t. This was needed to be able to handle off_t overflows properly. Also changed a few unsigned int fields into uoff_t so we should now support >2G mails if uoff_t is 64bit. Also fixed several potential integer overflows.
author Timo Sirainen <tss@iki.fi>
date Tue, 27 Aug 2002 22:16:54 +0300
parents 6be018ca51ef
children b4adc3429867
files acconfig.h configure.in src/imap/cmd-fetch.c src/lib-imap/imap-bodystructure.c src/lib-imap/imap-envelope.c src/lib-imap/imap-message-cache.c src/lib-imap/imap-message-cache.h src/lib-imap/imap-parser.c src/lib-imap/imap-parser.h src/lib-index/mail-hash.c src/lib-index/mail-hash.h src/lib-index/mail-index-compress.c src/lib-index/mail-index-data.c src/lib-index/mail-index-data.h src/lib-index/mail-index-fsck.c src/lib-index/mail-index-update.c src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-index/mail-messageset.c src/lib-index/mail-modifylog.c src/lib-index/maildir/maildir-sync.c src/lib-index/mbox/mbox-append.c src/lib-index/mbox/mbox-from.c src/lib-index/mbox/mbox-fsck.c src/lib-index/mbox/mbox-open.c src/lib-index/mbox/mbox-rebuild.c src/lib-index/mbox/mbox-sync.c src/lib-mail/message-parser.c src/lib-mail/message-parser.h src/lib-mail/message-send.c src/lib-mail/message-send.h src/lib-mail/message-size.c src/lib-mail/message-size.h src/lib-storage/flags-file/flags-file.c src/lib-storage/index/index-fetch-section.c src/lib-storage/index/index-fetch.c src/lib-storage/index/index-save.c src/lib-storage/index/index-search.c src/lib-storage/mail-storage.h src/lib/iobuffer.c src/lib/iobuffer.h src/lib/lib.h src/lib/strfuncs.c src/lib/temp-string.c src/master/main.c
diffstat 45 files changed, 378 insertions(+), 226 deletions(-) [+]
line wrap: on
line diff
--- a/acconfig.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/acconfig.h	Tue Aug 27 22:16:54 2002 +0300
@@ -21,3 +21,17 @@
 
 /* Required memory alignment */
 #undef MEM_ALIGN_SIZE
+
+/* If set to 64, enables 64bit off_t for some systems (eg. Linux, Solaris) */
+#undef _FILE_OFFSET_BITS
+
+/* Maximum value for uoff_t */
+#undef OFF_T_MAX
+
+/* printf()-format for uoff_t, eg. "u" or "lu" or "llu" */
+#undef UOFF_T_FORMAT
+
+/* What type should be used for uoff_t */
+#undef UOFF_T_INT
+#undef UOFF_T_LONG
+#undef UOFF_T_LONG_LONG
--- a/configure.in	Tue Aug 27 20:35:00 2002 +0300
+++ b/configure.in	Tue Aug 27 22:16:54 2002 +0300
@@ -94,7 +94,7 @@
 
 dnl * gcc specific options
 if test "x$ac_cv_prog_gcc" = "xyes"; then
-	# -W -Wchar-subscripts -Wpointer-arith -Wcast-align -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
+	# -Wchar-subscripts -Wpointer-arith -Wcast-align -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
 	CFLAGS="$CFLAGS -Wall -W"
 fi
 
@@ -107,6 +107,52 @@
 		;;
 esac
 
+dnl * off_t checks, try to make it 64bit
+preferred_off_t_bits=32
+AC_DEFINE_UNQUOTED(_FILE_OFFSET_BITS, $preferred_off_t_bits)
+
+AC_MSG_CHECKING([size of off_t])
+sizeof_off_t=0
+for size in 4 8; do
+  AC_TRY_RUN([
+    #define _FILE_OFFSET_BITS $preferred_off_t_bits
+    #include <sys/types.h>
+    #include <unistd.h>
+    int main() { off_t size; return sizeof(size) == $size ? 0 : 1; }
+  ], [
+    sizeof_off_t=$size
+    break
+  ])
+done
+
+if test x$sizeof_off_t = x0; then
+  AC_ERROR([Unsupported off_t size])
+fi
+AC_MSG_RESULT($sizeof_off_t)
+
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+
+if test x$sizeof_off_t = x$ac_cv_sizeof_long; then
+  # try to use unsigned long always first
+  AC_DEFINE_UNQUOTED(OFF_T_MAX, LONG_MAX)
+  AC_DEFINE_UNQUOTED(UOFF_T_FORMAT, "lu")
+  AC_DEFINE(UOFF_T_LONG)
+elif test x$sizeof_off_t = x$ac_cv_sizeof_int; then
+  # next try int
+  AC_DEFINE_UNQUOTED(OFF_T_MAX, INT_MAX)
+  AC_DEFINE_UNQUOTED(UOFF_T_FORMAT, "u")
+  AC_DEFINE(UOFF_T_INT)
+elif test x$sizeof_off_t = x$ac_cv_sizeof_long_long; then
+  # and finally long long
+  AC_DEFINE_UNQUOTED(OFF_T_MAX, LONG_LONG_MAX)
+  AC_DEFINE_UNQUOTED(UOFF_T_FORMAT, "llu")
+  AC_DEFINE(UOFF_T_LONG_LONG)
+else
+  AC_ERROR([Couldn't find integer type for off_t])
+fi
+
 dnl * memory alignment, could be 1 for x86 systems but 4 should be
 dnl * compatible with everyone. note that only 1, 2 and 4 work corrently.
 dnl * is 8 needed anywhere?
--- a/src/imap/cmd-fetch.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/imap/cmd-fetch.c	Tue Aug 27 22:16:54 2002 +0300
@@ -5,14 +5,14 @@
 
 /* Parse next digits in string into integer. Returns FALSE if the integer
    becomes too big and wraps. */
-static int read_int(char **p, unsigned int *value)
+static int read_uoff_t(char **p, uoff_t *value)
 {
-	unsigned int prev;
+	uoff_t prev;
+
 	*value = 0;
-
 	while (**p >= '0' && **p <= '9') {
 		prev = *value;
-		*value = *value * 10 + **p - '0';
+		*value = *value * 10 + (**p - '0');
 
 		if (*value < prev)
 			return FALSE;
@@ -28,7 +28,7 @@
 			      MailFetchData *data, int peek)
 {
 	MailFetchBodyData *body;
-	unsigned int num;
+	uoff_t num;
 	const char *section;
 	char *p;
 
@@ -50,7 +50,7 @@
 
 	/* <start.end> */
 	body->skip = 0;
-	body->max_size = -1;
+	body->max_size = (uoff_t)-1;
 	if (*p != '<' && *p != '\0') {
 		client_send_tagline(client, t_strconcat(
 			"BAD Unexpected character after ']' with ",
@@ -60,7 +60,7 @@
 		p++;
 
 		body->skip_set = TRUE;
-		if (!read_int(&p, &num) || num > INT_MAX) {
+		if (!read_uoff_t(&p, &num) || num > OFF_T_MAX) {
 			/* wrapped */
 			client_send_tagline(client, t_strconcat(
 				"BAD Too big partial start with ", item, NULL));
@@ -71,7 +71,7 @@
 		if (*p == '.') {
 			/* read end */
 			p++;
-			if (!read_int(&p, &num) || num > INT_MAX) {
+			if (!read_uoff_t(&p, &num) || num > OFF_T_MAX) {
 				/* wrapped */
 				client_send_tagline(client, t_strconcat(
 					"BAD Too big partial end with ",
--- a/src/lib-imap/imap-bodystructure.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-imap/imap-bodystructure.c	Tue Aug 27 22:16:54 2002 +0300
@@ -106,8 +106,8 @@
 
 static void parse_header(MessagePart *part,
 			 const char *name, unsigned int name_len,
-			 const char *value,
-			 unsigned int value_len, void *context)
+			 const char *value, unsigned int value_len,
+			 void *context)
 {
 	Pool pool = context;
 	MessagePartBodyData *part_data;
@@ -265,11 +265,11 @@
 		t_string_append_c(str, ')');
 	}
 
-	t_string_printfa(str, " %s %s %s %lu",
+	t_string_printfa(str, " %s %s %s %"UOFF_T_FORMAT,
 			 NVL(data->content_id, "NIL"),
 			 NVL(data->content_description, "NIL"),
 			 NVL(data->content_transfer_encoding, "\"8bit\""),
-			 (unsigned long) part->body_size.virtual_size);
+			 part->body_size.virtual_size);
 
 	if (part->text) {
 		/* text/.. contains line count */
--- a/src/lib-imap/imap-envelope.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-imap/imap-envelope.c	Tue Aug 27 22:16:54 2002 +0300
@@ -15,8 +15,8 @@
 	char *in_reply_to, *message_id;
 };
 
-static const char *t_buffer_get_quote(const char *value,
-				      unsigned int *value_len)
+static const char *
+t_buffer_get_quote(const char *value, unsigned int *value_len)
 {
 	char *buf, *p;
 	unsigned int i, len;
@@ -46,7 +46,7 @@
 
 	value_len = strlen(value);
 	buf = t_buffer_get_quote(value, &value_len);
-	t_buffer_alloc((unsigned int) value_len);
+	t_buffer_alloc(value_len);
 	return buf;
 }
 
--- a/src/lib-imap/imap-message-cache.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-imap/imap-message-cache.c	Tue Aug 27 22:16:54 2002 +0300
@@ -45,7 +45,7 @@
 
 	CachedMessage *open_msg;
 	IOBuffer *open_inbuf;
-	off_t open_virtual_size;
+	uoff_t open_virtual_size;
 
 	IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf, void *context);
 	void *context;
@@ -163,7 +163,7 @@
 	return NULL;
 }
 
-static void imap_msgcache_get_inbuf(ImapMessageCache *cache, off_t offset)
+static void imap_msgcache_get_inbuf(ImapMessageCache *cache, uoff_t offset)
 {
 	if (offset < cache->open_inbuf->offset) {
 		/* need to rewind */
@@ -292,9 +292,11 @@
 			message_get_header_size(cache->open_inbuf,
 						msg->hdr_size);
 
-			i_assert((off_t)msg->hdr_size->physical_size <
+			/* FIXME: this may actually happen if file size is
+			   shrinked.. */
+			i_assert(msg->hdr_size->physical_size <
 				 cache->open_inbuf->size);
-			i_assert((off_t)msg->hdr_size->virtual_size <
+			i_assert(msg->hdr_size->virtual_size <
 				 cache->open_virtual_size);
 
 			msg->body_size->lines = 0;
@@ -326,8 +328,8 @@
 }
 
 void imap_msgcache_message(ImapMessageCache *cache, unsigned int uid,
-			   ImapCacheField fields, off_t virtual_size,
-			   off_t pv_headers_size, off_t pv_body_size,
+			   ImapCacheField fields, uoff_t virtual_size,
+			   uoff_t pv_headers_size, uoff_t pv_body_size,
 			   IOBuffer *inbuf,
 			   IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf,
 						     void *context),
@@ -447,7 +449,7 @@
 			     IOBuffer **inbuf)
 {
 	CachedMessage *msg;
-	off_t offset;
+	uoff_t offset;
 
 	if (inbuf != NULL) {
 		if (cache->open_msg == NULL || cache->open_msg->uid != uid)
@@ -485,7 +487,7 @@
 }
 
 static void get_partial_size(IOBuffer *inbuf,
-			     off_t virtual_skip, off_t max_virtual_size,
+			     uoff_t virtual_skip, uoff_t max_virtual_size,
 			     MessageSize *partial, MessageSize *dest)
 {
 	unsigned char *msg;
@@ -493,7 +495,7 @@
 	int cr_skipped;
 
 	/* see if we can use the existing partial */
-	if ((off_t)partial->virtual_size > virtual_skip)
+	if (partial->virtual_size > virtual_skip)
 		memset(partial, 0, sizeof(MessageSize));
 	else {
 		io_buffer_skip(inbuf, partial->physical_size);
@@ -517,12 +519,13 @@
 }
 
 int imap_msgcache_get_rfc822_partial(ImapMessageCache *cache, unsigned int uid,
-				     off_t virtual_skip, off_t max_virtual_size,
+				     uoff_t virtual_skip,
+				     uoff_t max_virtual_size,
 				     int get_header, MessageSize *size,
                                      IOBuffer **inbuf)
 {
 	CachedMessage *msg;
-	off_t physical_skip;
+	uoff_t physical_skip;
 	int size_got;
 
 	msg = cache->open_msg;
@@ -540,7 +543,8 @@
 	/* see if we can do this easily */
 	size_got = FALSE;
 	if (virtual_skip == 0) {
-		if (max_virtual_size < 0 && msg->body_size == NULL) {
+		if (msg->body_size == NULL) {
+			/* FIXME: may underflow */
 			msg->body_size = p_new(msg->pool, MessageSize, 1);
 			msg->body_size->physical_size =
 				cache->open_inbuf->size -
@@ -550,9 +554,7 @@
 				msg->hdr_size->virtual_size;
 		}
 
-		if (msg->body_size != NULL &&
-		    (max_virtual_size < 0 ||
-		     max_virtual_size >= (off_t)msg->body_size->virtual_size)) {
+		if (max_virtual_size >= msg->body_size->virtual_size) {
 			*size = *msg->body_size;
 			size_got = TRUE;
 		}
--- a/src/lib-imap/imap-message-cache.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-imap/imap-message-cache.h	Tue Aug 27 22:16:54 2002 +0300
@@ -37,8 +37,8 @@
    non-zero, they're set to saved to message's both physical and virtual
    sizes (ie. doesn't need to be calculated). */
 void imap_msgcache_message(ImapMessageCache *cache, unsigned int uid,
-			   ImapCacheField fields, off_t virtual_size,
-			   off_t pv_headers_size, off_t pv_body_size,
+			   ImapCacheField fields, uoff_t virtual_size,
+			   uoff_t pv_headers_size, uoff_t pv_body_size,
 			   IOBuffer *inbuf,
 			   IOBuffer *(*inbuf_rewind)(IOBuffer *inbuf,
 						     void *context),
@@ -68,7 +68,8 @@
 /* Returns FALSE if message isn't in cache. *inbuf is set to point to the first
    non-skipped character. size is set to specify the full size of message. */
 int imap_msgcache_get_rfc822_partial(ImapMessageCache *cache, unsigned int uid,
-				     off_t virtual_skip, off_t max_virtual_size,
+				     uoff_t virtual_skip,
+				     uoff_t max_virtual_size,
 				     int get_header, MessageSize *size,
 				     IOBuffer **inbuf);
 
--- a/src/lib-imap/imap-parser.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-imap/imap-parser.c	Tue Aug 27 22:16:54 2002 +0300
@@ -31,7 +31,7 @@
 
         ImapParserFlags flags;
 	int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
-	unsigned int literal_size; /* ARG_PARSE_LITERAL: string size */
+	uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */
 	unsigned int literal_skip_crlf:1;
 
 	unsigned int inside_bracket:1;
@@ -304,7 +304,7 @@
 			return FALSE;
 
 		prev_size = parser->literal_size;
-		parser->literal_size = parser->literal_size*10 + data[i]-'0';
+		parser->literal_size = parser->literal_size*10 + (data[i]-'0');
 
 		if (parser->literal_size < prev_size) {
 			/* wrapped around, abort. */
@@ -344,7 +344,7 @@
 		if (data_size >= parser->literal_size) {
 			imap_parser_save_arg(parser, data,
 					     parser->literal_size);
-			parser->cur_pos = parser->literal_size;
+			parser->cur_pos = (unsigned int) parser->literal_size;
 		}
 	} else {
 		/* we want to save only literal size, not the literal itself. */
--- a/src/lib-imap/imap-parser.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-imap/imap-parser.h	Tue Aug 27 22:16:54 2002 +0300
@@ -27,7 +27,7 @@
 
 	union {
 		char *str;
-		unsigned int literal_size;
+		uoff_t literal_size;
 		ImapArgList *list;
 	} data;
 };
--- a/src/lib-index/mail-hash.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-hash.c	Tue Aug 27 22:16:54 2002 +0300
@@ -195,6 +195,8 @@
 	int ret, old_errno;
 	off_t pos;
 
+	i_assert(size >= 0);
+
 	/* try truncating it to the size we want. if this succeeds, the written
 	   area is full of zeros - exactly what we want. however, this may not
 	   work at all, in which case we fallback to write()ing the zeros. */
@@ -246,7 +248,7 @@
 
 	/* fill the file with zeros */
 	new_size = sizeof(MailHashHeader) + hash_size * sizeof(MailHashRecord);
-	if (!file_set_size(fd, (off_t) new_size)) {
+	if (!file_set_size(fd, (off_t)new_size)) {
 		index_set_error(index,
 				"Failed to fill temp hash to size %lu: %m",
 				(unsigned long) new_size);
@@ -372,7 +374,7 @@
 	return TRUE;
 }
 
-off_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid)
+uoff_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid)
 {
         MailHashRecord *rec;
 	unsigned int hashidx, idx;
@@ -439,7 +441,7 @@
 	return NULL;
 }
 
-void mail_hash_update(MailHash *hash, unsigned int uid, off_t pos)
+void mail_hash_update(MailHash *hash, unsigned int uid, uoff_t pos)
 {
 	MailHashRecord *rec;
 	unsigned int max_used;
--- a/src/lib-index/mail-hash.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-hash.h	Tue Aug 27 22:16:54 2002 +0300
@@ -12,7 +12,7 @@
 
 struct _MailHashRecord {
 	unsigned int uid;
-	off_t position;
+	uoff_t position;
 };
 
 /* Open or create a hash file for index. If the hash needs to be created,
@@ -30,10 +30,10 @@
 int mail_hash_rebuild(MailHash *hash);
 
 /* Returns position in index file to given UID, or 0 if not found. */
-off_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid);
+uoff_t mail_hash_lookup_uid(MailHash *hash, unsigned int uid);
 
 /* Update hash file. If pos is 0, the record is deleted. This call may
    rebuild the hash if it's too full. */
-void mail_hash_update(MailHash *hash, unsigned int uid, off_t pos);
+void mail_hash_update(MailHash *hash, unsigned int uid, uoff_t pos);
 
 #endif
--- a/src/lib-index/mail-index-compress.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index-compress.c	Tue Aug 27 22:16:54 2002 +0300
@@ -23,7 +23,7 @@
 		return TRUE;
 	}
 
-	if (index->header->first_hole_position >= (off_t)index->mmap_length) {
+	if (index->header->first_hole_position >= index->mmap_length) {
 		index_set_error(index, "Error in index file %s: "
 				"first_hole_position points outside file",
 				index->filepath);
@@ -78,7 +78,7 @@
 	MailIndexRecord *rec;
 	unsigned char *mmap_data;
 	size_t mmap_data_size;
-	off_t offset;
+	uoff_t offset;
 
 	mmap_data = mail_index_data_get_mmaped(index->data, &mmap_data_size);
 	if (mmap_data == NULL)
--- a/src/lib-index/mail-index-data.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index-data.c	Tue Aug 27 22:16:54 2002 +0300
@@ -11,7 +11,7 @@
 #include <fcntl.h>
 
 #define DATA_FILE_POSITION(data, rec) \
-	((off_t) ((char *) (rec) - (char *) ((data)->mmap_base)))
+	((uoff_t) ((char *) (rec) - (char *) ((data)->mmap_base)))
 
 /* Never compress the file if it's smaller than this (50kB) */
 #define COMPRESS_MIN_SIZE (1024*50)
@@ -31,9 +31,10 @@
 	unsigned int dirty_mmap:1;
 };
 
-static int mmap_update(MailIndexData *data, off_t pos, unsigned int size)
+static int mmap_update(MailIndexData *data, uoff_t pos, unsigned int size)
 {
-	if (!data->dirty_mmap || (size != 0 && pos+size <= data->mmap_length))
+	if (!data->dirty_mmap || (size != 0 && pos <= data->mmap_length &&
+				  pos+size <= data->mmap_length))
 		return TRUE;
 
 	if (data->mmap_base != NULL)
@@ -203,8 +204,8 @@
 	data->dirty_mmap = TRUE;
 }
 
-off_t mail_index_data_append(MailIndexData *data, const void *buffer,
-			     size_t size)
+uoff_t mail_index_data_append(MailIndexData *data, const void *buffer,
+			      size_t size)
 {
 	off_t pos;
 
@@ -214,24 +215,30 @@
 	if (pos == -1) {
 		index_set_error(data->index, "lseek() failed with file %s: %m",
 				data->filepath);
-		return -1;
+		return 0;
+	}
+
+	if (pos < (int)sizeof(MailIndexDataHeader)) {
+		index_set_error(data->index, "Header missing from data file %s",
+				data->filepath);
+		return 0;
 	}
 
 	if (write_full(data->fd, buffer, size) < 0) {
 		index_set_error(data->index, "Error appending to file %s: %m",
 				data->filepath);
-		return -1;
+		return 0;
 	}
 
 	mail_index_data_new_data_notify(data);
-	return pos;
+	return (uoff_t)pos;
 }
 
 int mail_index_data_add_deleted_space(MailIndexData *data,
 				      unsigned int data_size)
 {
 	MailIndexDataHeader *hdr;
-	off_t max_del_space;
+	uoff_t max_del_space;
 
 	i_assert(data->index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
@@ -275,9 +282,10 @@
 		       MailField field)
 {
 	MailIndexDataRecord *rec;
-	off_t pos, max_pos;
+	uoff_t pos, max_pos;
 
 	if (index_rec->data_position == 0) {
+		/* data not yet written to record */
 		index_reset_error(data->index);
 		return NULL;
 	}
@@ -285,38 +293,36 @@
 	if (!mmap_update(data, index_rec->data_position, index_rec->data_size))
 		return NULL;
 
-	max_pos = index_rec->data_position + (off_t)index_rec->data_size;
-	if (max_pos > (off_t)data->mmap_length) {
+	if (index_rec->data_position > data->mmap_length ||
+	    (data->mmap_length -
+	     index_rec->data_position > index_rec->data_size)) {
 		INDEX_MARK_CORRUPTED(data->index);
 		index_set_error(data->index, "Error in data file %s: "
 				"Given data size larger than file size "
-				"(%lu > %lu)", data->filepath,
-				(unsigned long) max_pos,
+				"(%lu + %u > %lu)", data->filepath,
+				(unsigned long) index_rec->data_position,
+                                index_rec->data_size,
 				(unsigned long) data->mmap_length);
 		return NULL;
 	}
 
 	pos = index_rec->data_position;
+	max_pos = pos + index_rec->data_size;
+
 	do {
-		if (pos + (off_t)sizeof(MailIndexDataRecord) > max_pos) {
-			INDEX_MARK_CORRUPTED(data->index);
-			index_set_error(data->index, "Error in data file %s: "
-					"Index points outside file "
-					"(%lu > %lu)", data->filepath,
-					(unsigned long) pos,
-					(unsigned long) data->mmap_length);
-			break;
-		}
+		rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos);
 
-		rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos);
-		if (pos + (off_t)DATA_RECORD_SIZE(rec) > max_pos) {
+		/* pos + DATA_RECORD_SIZE() may actually overflow, but it
+		   points to beginning of file then. Don't bother checking
+		   this as it won't crash and is quite likely noticed later. */
+		if (pos + sizeof(MailIndexDataRecord) > max_pos ||
+		    pos + DATA_RECORD_SIZE(rec) > max_pos) {
 			INDEX_MARK_CORRUPTED(data->index);
 			index_set_error(data->index, "Error in data file %s: "
 					"Field size points outside file "
-					"(%lu + %u > %lu)", data->filepath,
+					"(%lu / %lu)", data->filepath,
 					(unsigned long) pos,
-					rec->full_field_size,
-					(unsigned long) data->mmap_length);
+					(unsigned long) max_pos);
 			break;
 		}
 
@@ -340,7 +346,7 @@
 mail_index_data_next(MailIndexData *data, MailIndexRecord *index_rec,
 		     MailIndexDataRecord *rec)
 {
-	off_t pos, max_pos;
+	uoff_t pos, end_pos, max_pos;
 
 	if (rec == NULL)
 		return NULL;
@@ -354,14 +360,15 @@
 		return NULL;
 
 	rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos);
-	if (pos + (off_t)DATA_RECORD_SIZE(rec) > max_pos) {
+	end_pos = pos + DATA_RECORD_SIZE(rec);
+	if (end_pos < pos || end_pos > max_pos) {
 		INDEX_MARK_CORRUPTED(data->index);
 		index_set_error(data->index, "Error in data file %s: "
 				"Field size points outside file "
 				"(%lu + %u > %lu)", data->filepath,
 				(unsigned long) pos,
 				rec->full_field_size,
-				(unsigned long) data->mmap_length);
+				(unsigned long) max_pos);
 		return NULL;
 	}
 
@@ -372,8 +379,15 @@
 {
 	int i;
 
+	if (rec->full_field_size > INT_MAX) {
+		INDEX_MARK_CORRUPTED(data->index);
+		index_set_error(data->index, "Error in data file %s: "
+				"full_field_size > INT_MAX", data->filepath);
+		return FALSE;
+	}
+
 	/* make sure the data actually contains \0 */
-	for (i = rec->full_field_size-1; i >= 0; i--) {
+	for (i = (int)rec->full_field_size-1; i >= 0; i--) {
 		if (rec->data[i] == '\0') {
 			/* yes, everything ok */
 			return TRUE;
--- a/src/lib-index/mail-index-data.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index-data.h	Tue Aug 27 22:16:54 2002 +0300
@@ -15,9 +15,9 @@
 void mail_index_data_new_data_notify(MailIndexData *data);
 
 /* Append new data at the end of the file. Returns the position in file
-   where the data begins, or (off_t)-1 if error occured. */
-off_t mail_index_data_append(MailIndexData *data, const void *buffer,
-			     size_t size);
+   where the data begins, or 0 if error occured. */
+uoff_t mail_index_data_append(MailIndexData *data, const void *buffer,
+			      size_t size);
 
 /* Increase header->deleted_space field */
 int mail_index_data_add_deleted_space(MailIndexData *data,
--- a/src/lib-index/mail-index-fsck.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index-fsck.c	Tue Aug 27 22:16:54 2002 +0300
@@ -10,7 +10,7 @@
 	MailIndexHeader *hdr;
 	MailIndexRecord *rec, *end_rec;
 	unsigned int max_uid;
-	off_t pos;
+	uoff_t pos;
 
 	i_assert(index->lock_type != MAIL_LOCK_SHARED);
 
@@ -42,9 +42,9 @@
 			if (hdr->first_hole_position == 0) {
 				hdr->first_hole_position = pos;
 				hdr->first_hole_records = 1;
-			} else if ((off_t) (hdr->first_hole_position +
-					    (hdr->first_hole_records *
-					     sizeof(MailIndexRecord))) == pos) {
+			} else if (hdr->first_hole_position +
+				   (hdr->first_hole_records *
+				    sizeof(MailIndexRecord)) == pos) {
 				/* hole continues */
 				hdr->first_hole_records++;
 			}
--- a/src/lib-index/mail-index-update.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index-update.c	Tue Aug 27 22:16:54 2002 +0300
@@ -73,11 +73,21 @@
 static int have_too_large_fields(MailIndexUpdate *update)
 {
 	MailIndexDataRecord *rec;
+	unsigned int size_left;
 	int index;
 
+	size_left = update->rec->data_size;
+
 	/* start from the first data field - it's required to exist */
 	rec = mail_index_data_lookup(update->index->data, update->rec, 1);
 	while (rec != NULL) {
+		if (rec->full_field_size > size_left) {
+			/* corrupted */
+			update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
+			return TRUE;
+		}
+		size_left -= rec->full_field_size;
+
 		if (rec->field & update->updated_fields) {
 			/* field was changed */
 			index = mail_field_get_index(rec->field);
@@ -99,22 +109,36 @@
 {
         MailIndexDataRecord *rec, *destrec;
 	MailField field;
-	off_t fpos;
+	uoff_t fpos;
 	void *mem;
-	unsigned int max_size, pos;
+	const void *src;
+	unsigned int max_size, pos, src_size;
 	int i;
 
 	/* allocate the old size + also the new size of all changed or added
 	   fields. this is more than required, but it's much easier than
-	   calculating the exact size. */
+	   calculating the exact size.
+
+	   If this calculation overflows (no matter what value), it doesn't
+	   really matter as it's later checked anyway. */
 	max_size = update->rec->data_size;
 	for (i = 0; i < FIELD_TYPE_MAX_BITS; i++) {
-		max_size += sizeof(MailIndexDataRecord)-sizeof(rec->data) +
+		max_size += SIZEOF_MAIL_INDEX_DATA +
 			update->field_sizes[i] +
 			update->field_extra_sizes[i] + MEM_ALIGN_SIZE-1;
 	}
 
-	mem = p_malloc(update->pool, max_size);
+	if (max_size > INT_MAX) {
+		/* rec->data_size most likely corrupted */
+		update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
+		return FALSE;
+	}
+
+	/* allocate two extra records to avoid overflows in case of bad
+	   rec->full_field_size which itself fits into max_size, but
+	   either the record part would make it point ouside allocate memory,
+	   or the next field's record would do that */
+	mem = p_malloc(update->pool, max_size + sizeof(MailIndexDataRecord)*2);
 	pos = 0;
 
 	rec = mail_index_data_lookup(update->index->data, update->rec, 1);
@@ -125,17 +149,26 @@
 			/* value was modified - use it */
 			destrec->full_field_size = update->field_sizes[i] +
 				update->field_extra_sizes[i];
-			memcpy(destrec->data, update->fields[i],
-			       update->field_sizes[i]);
+			src = update->fields[i];
+			src_size = update->field_sizes[i];
 		} else if (rec != NULL) {
 			/* use the old value */
 			destrec->full_field_size = rec->full_field_size;
-			memcpy(destrec->data, rec->data, rec->full_field_size);
+			src = rec->data;
+			src_size = rec->full_field_size;
 		} else {
 			/* the field doesn't exist, jump to next */
 			continue;
 		}
 
+		if (src_size > max_size || max_size - src_size > pos) {
+			/* corrupted data file - old value had a field
+			   larger than expected */
+			update->index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
+			return FALSE;
+		}
+		memcpy(destrec->data, src, src_size);
+
 		/* memory alignment fix */
 		destrec->full_field_size = MEM_ALIGN(destrec->full_field_size);
 
@@ -152,7 +185,7 @@
 
 	/* append the data at the end of the data file */
 	fpos = mail_index_data_append(update->index->data, mem, pos);
-	if (fpos == -1)
+	if (fpos == 0)
 		return FALSE;
 
 	/* update index file position - it's mmap()ed so it'll be writte
@@ -177,10 +210,11 @@
 			index = mail_field_get_index(rec->field);
 			i_assert(index >= 0);
 
-			i_assert(update->field_sizes[index] <
+			i_assert(update->field_sizes[index] <=
 				 rec->full_field_size);
 
-			strcpy(rec->data, update->fields[index]);
+			memcpy(rec->data, update->fields[index],
+			       update->field_sizes[index]);
 		}
 		rec = mail_index_data_next(update->index->data,
 					   update->rec, rec);
@@ -391,7 +425,7 @@
 			/* we need to calculate virtual size of the
 			   body as well. message_parse_header() left the
 			   inbuf point to beginning of the body. */
-			message_get_body_size(inbuf, &body_size, -1);
+			message_get_body_size(inbuf, &body_size, (uoff_t)-1);
 
 			update->rec->full_virtual_size =
 				hdr_size.virtual_size + body_size.virtual_size;
--- a/src/lib-index/mail-index.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index.c	Tue Aug 27 22:16:54 2002 +0300
@@ -53,7 +53,7 @@
 		/* partial write or corrupted -
 		   truncate the file to valid length */
 		index->mmap_length -= extra;
-		(void)ftruncate(index->fd, (off_t) index->mmap_length);
+		(void)ftruncate(index->fd, (off_t)index->mmap_length);
 	}
 
 	index->header = (MailIndexHeader *) index->mmap_base;
@@ -371,7 +371,7 @@
 	if (hdr->compat_data[0] != MAIL_INDEX_COMPAT_FLAGS ||
 	    hdr->compat_data[1] != sizeof(unsigned int) ||
 	    hdr->compat_data[2] != sizeof(time_t) ||
-	    hdr->compat_data[3] != sizeof(off_t))
+	    hdr->compat_data[3] != sizeof(uoff_t))
 		return FALSE;
 
 	/* check the version */
@@ -575,7 +575,7 @@
 	hdr->compat_data[0] = MAIL_INDEX_COMPAT_FLAGS;
 	hdr->compat_data[1] = sizeof(unsigned int);
 	hdr->compat_data[2] = sizeof(time_t);
-	hdr->compat_data[3] = sizeof(off_t);
+	hdr->compat_data[3] = sizeof(uoff_t);
 	hdr->version = MAIL_INDEX_VERSION;
 	hdr->indexid = ioloop_time;
 
@@ -759,7 +759,7 @@
 	MailIndexHeader *hdr;
 	MailIndexRecord *rec, *end_rec;
 	unsigned int seq;
-	off_t seekpos;
+	uoff_t seekpos;
 
 	if (lookup_seq == index->last_lookup_seq &&
 	    index->last_lookup != NULL && index->last_lookup->uid != 0) {
@@ -772,8 +772,8 @@
 				   sizeof(MailIndexHeader));
 
 	seekpos = sizeof(MailIndexHeader) +
-		(off_t)(lookup_seq-1) * sizeof(MailIndexRecord);
-	if (seekpos > (off_t) (index->mmap_length - sizeof(MailIndexRecord))) {
+		(uoff_t)(lookup_seq-1) * sizeof(MailIndexRecord);
+	if (seekpos > index->mmap_length - sizeof(MailIndexRecord)) {
 		/* out of range */
 		return NULL;
 	}
@@ -865,7 +865,7 @@
 {
 	MailIndexRecord *rec, *end_rec;
 	unsigned int uid, last_try_uid;
-	off_t pos;
+	uoff_t pos;
 
 	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
 	i_assert(first_uid > 0 && last_uid > 0);
@@ -1045,7 +1045,7 @@
 static int mail_index_truncate(MailIndex *index)
 {
 	/* truncate index file */
-	if (ftruncate(index->fd, index->header->first_hole_position) < 0)
+	if (ftruncate(index->fd, (off_t)index->header->first_hole_position) < 0)
 		return FALSE;
 
 	/* update header */
@@ -1069,7 +1069,7 @@
 		       unsigned int seq, int external_change)
 {
 	MailIndexHeader *hdr;
-	off_t pos;
+	uoff_t pos;
 
 	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
 	i_assert(rec->uid != 0);
@@ -1103,14 +1103,12 @@
 		/* first deleted message in index */
 		hdr->first_hole_position = pos;
 		hdr->first_hole_records = 1;
-	} else if ((off_t) (hdr->first_hole_position -
-			    sizeof(MailIndexRecord)) == pos) {
+	} else if (hdr->first_hole_position - sizeof(MailIndexRecord) == pos) {
 		/* deleted the previous record before hole */
 		hdr->first_hole_position -= sizeof(MailIndexRecord);
 		hdr->first_hole_records++;
-	} else if ((off_t) (hdr->first_hole_position +
-			    (hdr->first_hole_records *
-			     sizeof(MailIndexRecord))) == pos) {
+	} else if (hdr->first_hole_position +
+		   (hdr->first_hole_records * sizeof(MailIndexRecord)) == pos) {
 		/* deleted the next record after hole */
 		hdr->first_hole_records++;
 		update_first_hole_records(index);
@@ -1169,7 +1167,7 @@
 	(*rec)->uid = index->header->next_uid++;
 
 	pos = lseek(index->fd, 0, SEEK_END);
-	if (pos == -1) {
+	if (pos < 0) {
 		index_set_error(index, "lseek() failed with file %s: %m",
 				index->filepath);
 		return FALSE;
@@ -1185,7 +1183,7 @@
         index_mark_flag_changes(index, *rec, 0, (*rec)->msg_flags);
 
 	if (index->hash != NULL)
-		mail_hash_update(index->hash, (*rec)->uid, pos);
+		mail_hash_update(index->hash, (*rec)->uid, (uoff_t)pos);
 
 	index->dirty_mmap = TRUE;
 	if (!mmap_update(index))
--- a/src/lib-index/mail-index.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-index.h	Tue Aug 27 22:16:54 2002 +0300
@@ -76,7 +76,7 @@
 	/* 0 = flags,
 	   1 = sizeof(unsigned int),
 	   2 = sizeof(time_t),
-	   3 = sizeof(off_t) */
+	   3 = sizeof(uoff_t) */
 
 	unsigned int version;
 	unsigned int indexid;
@@ -84,7 +84,7 @@
 	unsigned int flags;
 	unsigned int cache_fields;
 
-	off_t first_hole_position;
+	uoff_t first_hole_position;
 	unsigned int first_hole_records;
 
 	unsigned int uid_validity;
@@ -104,7 +104,7 @@
 
 struct _MailIndexDataHeader {
 	unsigned int indexid;
-	off_t deleted_space;
+	uoff_t deleted_space;
 };
 
 struct _MailIndexRecord {
@@ -113,13 +113,13 @@
 	time_t internal_date;
 	time_t sent_date;
 
-	off_t data_position;
+	uoff_t data_position;
 	unsigned int data_size;
 
 	unsigned int cached_fields;
-	off_t header_size;
-	off_t body_size;
-	off_t full_virtual_size;
+	uoff_t header_size;
+	uoff_t body_size;
+	uoff_t full_virtual_size;
 };
 
 #define MSG_HAS_VALID_CRLF_DATA(rec) \
@@ -131,8 +131,11 @@
 	char data[MEM_ALIGN_SIZE]; /* variable size */
 };
 
+#define SIZEOF_MAIL_INDEX_DATA \
+	(sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE)
+
 #define DATA_RECORD_SIZE(rec) \
-        (sizeof(MailIndexDataRecord) - MEM_ALIGN_SIZE + (rec)->full_field_size)
+        (SIZEOF_MAIL_INDEX_DATA + (rec)->full_field_size)
 
 struct _MailIndex {
 	int (*open)(MailIndex *index, int update_recent);
@@ -272,7 +275,7 @@
 	unsigned int indexid;
 
 	char *mbox_path; /* mbox-specific path to the actual mbox file */
-	off_t mbox_size; /* last synced size of mbox file */
+	uoff_t mbox_size; /* last synced size of mbox file */
 	int mbox_locks;
 
 	int fd; /* opened index file */
@@ -354,11 +357,11 @@
 /* Max. mmap()ed size for a message */
 #define MAIL_MMAP_BLOCK_SIZE (1024*256)
 
-/* off_t to index file for given record */
+/* uoff_t to index file for given record */
 #define INDEX_FILE_POSITION(index, ptr) \
-	((off_t) ((char *) (ptr) - (char *) ((index)->mmap_base)))
+	((uoff_t) ((char *) (ptr) - (char *) ((index)->mmap_base)))
 
-/* index number for off_t position */
+/* index number for uoff_t position */
 #define INDEX_POSITION_INDEX(pos) \
 	(((pos) - sizeof(MailIndexHeader)) / sizeof(MailIndexRecord))
 
--- a/src/lib-index/mail-messageset.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-messageset.c	Tue Aug 27 22:16:54 2002 +0300
@@ -16,7 +16,7 @@
 		if (**str < '0' || **str > '9')
 			break;
 
-		num = num*10 + **str - '0';
+		num = num*10 + (**str - '0');
 		(*str)++;
 	}
 
@@ -172,7 +172,7 @@
 				  const char **error)
 {
 	MailIndexRecord *rec;
-	off_t pos;
+	uoff_t pos;
 	const unsigned int *expunges;
 	unsigned int seq;
 	int expunges_found;
--- a/src/lib-index/mail-modifylog.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mail-modifylog.c	Tue Aug 27 22:16:54 2002 +0300
@@ -134,7 +134,7 @@
 		/* partial write or corrupted -
 		   truncate the file to valid length */
 		log->mmap_length -= extra;
-		(void)ftruncate(log->fd, (off_t) log->mmap_length);
+		(void)ftruncate(log->fd, (off_t)log->mmap_length);
 	}
 
 	log->dirty_mmap = FALSE;
--- a/src/lib-index/maildir/maildir-sync.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/maildir/maildir-sync.c	Tue Aug 27 22:16:54 2002 +0300
@@ -151,8 +151,8 @@
 				return FALSE;
 			}
 
-			file_changed = st.st_size != (off_t) (rec->body_size +
-							      rec->header_size);
+			file_changed = (uoff_t)st.st_size !=
+				rec->body_size + rec->header_size;
 		}
 
 		/* changed - update */
--- a/src/lib-index/mbox/mbox-append.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mbox/mbox-append.c	Tue Aug 27 22:16:54 2002 +0300
@@ -81,7 +81,7 @@
 	MailIndexUpdate *update;
         MboxHeaderContext ctx;
 	time_t internal_date;
-	off_t start_offset, stop_offset, old_size;
+	uoff_t start_offset, stop_offset, old_size;
 	unsigned char *data, md5_digest[16];
 	unsigned int size, pos, virtual_size;
 	const char *location;
--- a/src/lib-index/mbox/mbox-from.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mbox/mbox-from.c	Tue Aug 27 22:16:54 2002 +0300
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "mbox-index.h"
 
 #include <time.h>
 #include <ctype.h>
@@ -94,7 +95,7 @@
 {
 	struct tm *tm;
 	char *ret, *p;
-	int len, year;
+	unsigned int len, year;
 
 	len = strlen(sender);
 	ret = t_malloc(len + 24 + 1);
--- a/src/lib-index/mbox/mbox-fsck.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mbox/mbox-fsck.c	Tue Aug 27 22:16:54 2002 +0300
@@ -37,7 +37,7 @@
 {
 	MessageSize hdr_size;
 	MboxHeaderContext ctx;
-	off_t body_offset;
+	uoff_t body_offset;
 	unsigned char *data, current_digest[16], old_digest[16];
 	unsigned int size;
 	const char *md5sum;
@@ -101,7 +101,7 @@
 static int mbox_index_fsck_buf(MailIndex *index, IOBuffer *inbuf)
 {
 	MailIndexRecord *rec;
-	off_t from_offset;
+	uoff_t from_offset;
 	unsigned char *data;
 	unsigned int seq, size;
 
@@ -178,7 +178,7 @@
 	}
 
 	inbuf = io_buffer_create_mmap(fd, default_pool,
-				      MAIL_MMAP_BLOCK_SIZE, -1);
+				      MAIL_MMAP_BLOCK_SIZE, 0);
 
 	/* lock the mailbox so we can be sure no-one interrupts us.
 	   we are trying to repair our index after all. */
--- a/src/lib-index/mbox/mbox-open.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mbox/mbox-open.c	Tue Aug 27 22:16:54 2002 +0300
@@ -13,7 +13,8 @@
 IOBuffer *mbox_open_mail(MailIndex *index, MailIndexRecord *rec)
 {
 	const char *location;
-	off_t pos, offset, stop_offset;
+	uoff_t offset, stop_offset;
+	off_t pos;
 	char buf[7], *p;
 	int fd, ret, failed;
 
@@ -30,7 +31,8 @@
 
 	/* location = offset in hex */
 	if (strlen(location) != sizeof(offset)*2 ||
-	    hex_to_binary(location, (unsigned char *) &offset) <= 0) {
+	    hex_to_binary(location, (unsigned char *) &offset) <= 0 ||
+	    offset > OFF_T_MAX) {
                 INDEX_MARK_CORRUPTED(index);
 		index_set_error(index, "Corrupted index file %s: "
 				"Invalid location field for record %u",
@@ -47,7 +49,7 @@
 		return NULL;
 	}
 
-	pos = lseek(fd, offset, SEEK_SET);
+	pos = lseek(fd, (off_t)offset, SEEK_SET);
 	if (pos == -1) {
 		index_set_error(index, "lseek() failed with mbox file %s: %m",
 				index->mbox_path);
@@ -56,9 +58,10 @@
 	}
 
 	failed = TRUE;
-	if (pos == offset) {
+	if ((uoff_t)pos == offset) {
 		/* make sure message size is valid */
-		if (lseek(fd, stop_offset, SEEK_SET) == stop_offset) {
+		if (lseek(fd, (off_t)stop_offset, SEEK_SET) ==
+		    (off_t)stop_offset) {
 			/* and check that we end with either EOF or to
 			   beginning of next message */
 			ret = read(fd, buf, 7);
@@ -79,7 +82,7 @@
 	}
 
 	if (!failed) {
-		if (lseek(fd, offset, SEEK_SET) == offset) {
+		if (lseek(fd, (off_t)offset, SEEK_SET) == (off_t)offset) {
 			/* everything ok */
 			return io_buffer_create_mmap(fd, default_pool,
 						     MAIL_MMAP_BLOCK_SIZE,
--- a/src/lib-index/mbox/mbox-rebuild.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mbox/mbox-rebuild.c	Tue Aug 27 22:16:54 2002 +0300
@@ -67,7 +67,7 @@
 	}
 
 	inbuf = io_buffer_create_mmap(fd, default_pool,
-				      MAIL_MMAP_BLOCK_SIZE, -1);
+				      MAIL_MMAP_BLOCK_SIZE, 0);
 	if (!mbox_index_append(index, inbuf)) {
 		(void)mbox_unlock(index, index->mbox_path, fd);
 		(void)close(fd);
--- a/src/lib-index/mbox/mbox-sync.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-index/mbox/mbox-sync.c	Tue Aug 27 22:16:54 2002 +0300
@@ -11,11 +11,11 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
-static off_t get_indexed_mbox_size(MailIndex *index)
+static uoff_t get_indexed_mbox_size(MailIndex *index)
 {
 	MailIndexRecord *rec, *prev;
 	const char *location;
-	off_t size;
+	uoff_t size;
 
 	if (index->lock_type == MAIL_LOCK_UNLOCK) {
 		if (!mail_index_set_lock(index, MAIL_LOCK_SHARED))
@@ -59,6 +59,12 @@
 
 	if (index->lock_type == MAIL_LOCK_SHARED)
 		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
+
+	if (size > OFF_T_MAX) {
+		/* too large to fit in off_t */
+		return 0;
+	}
+
 	return size;
 }
 
@@ -75,7 +81,7 @@
 		return FALSE;
 	}
 
-	pos = lseek(fd, index->mbox_size, SEEK_SET);
+	pos = lseek(fd, (off_t)index->mbox_size, SEEK_SET);
 	if (pos == -1) {
 		index_set_error(index, "lseek() failed with mbox file %s: %m",
 				index->mbox_path);
@@ -83,7 +89,7 @@
 		return FALSE;
 	}
 
-	if (pos != index->mbox_size) {
+	if ((uoff_t)pos != index->mbox_size) {
 		/* someone just shrinked the file? */
 		(void)close(fd);
 		return mbox_index_fsck(index);
@@ -91,7 +97,7 @@
 
 	/* add the new data */
 	inbuf = io_buffer_create_mmap(fd, default_pool,
-				      MAIL_MMAP_BLOCK_SIZE, -1);
+				      MAIL_MMAP_BLOCK_SIZE, 0);
 	ret = mbox_index_append(index, inbuf);
 	(void)close(fd);
 	io_buffer_destroy(inbuf);
@@ -126,7 +132,7 @@
 		index->mbox_size = get_indexed_mbox_size(index);
 
 	/* file has been modified. */
-	if (index->mbox_size > st.st_size) {
+	if (index->mbox_size > (uoff_t)st.st_size) {
 		/* file was grown, hopefully just new mail */
 		return mbox_check_new_mail(index);
 	} else {
--- a/src/lib-mail/message-parser.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-mail/message-parser.c	Tue Aug 27 22:16:54 2002 +0300
@@ -188,7 +188,7 @@
 				       MessageParseContext *parse_ctx)
 {
 	MessagePart *next_part, *part;
-	size_t hdr_size;
+	uoff_t hdr_size;
 
 	message_parse_header(parse_ctx->part, inbuf,
 			     &parse_ctx->part->header_size,
@@ -550,7 +550,7 @@
 	MessageBoundary *boundary;
 
 	if (boundaries == NULL) {
-		message_get_body_size(inbuf, body_size, -1);
+		message_get_body_size(inbuf, body_size, (uoff_t)-1);
 		return NULL;
 	} else {
 		boundary = message_find_boundary(inbuf, boundaries,
--- a/src/lib-mail/message-parser.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-mail/message-parser.h	Tue Aug 27 22:16:54 2002 +0300
@@ -6,13 +6,13 @@
 typedef struct _MessageSize MessageSize;
 
 struct _MessagePosition {
-	off_t physical_pos;
-	off_t virtual_pos;
+	uoff_t physical_pos;
+	uoff_t virtual_pos;
 };
 
 struct _MessageSize {
-	size_t physical_size;
-	size_t virtual_size;
+	uoff_t physical_size;
+	uoff_t virtual_size;
 	unsigned int lines;
 };
 
--- a/src/lib-mail/message-send.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-mail/message-send.c	Tue Aug 27 22:16:54 2002 +0300
@@ -8,18 +8,17 @@
 #define OUTPUT_BUFFER_SIZE 1024
 
 int message_send(IOBuffer *outbuf, IOBuffer *inbuf, MessageSize *msg_size,
-		 off_t virtual_skip, off_t max_virtual_size)
+		 uoff_t virtual_skip, uoff_t max_virtual_size)
 {
 	unsigned char *msg, buf[OUTPUT_BUFFER_SIZE];
 	unsigned int i, size, pos;
 	int cr_skipped, add_cr;
 
 	if (msg_size->physical_size == 0 ||
-	    virtual_skip >= (off_t)msg_size->virtual_size)
+	    virtual_skip >= msg_size->virtual_size)
 		return TRUE;
 
-	if (max_virtual_size == -1 ||
-	    max_virtual_size > (off_t)msg_size->virtual_size - virtual_skip)
+	if (max_virtual_size > msg_size->virtual_size - virtual_skip)
 		max_virtual_size = msg_size->virtual_size - virtual_skip;
 
 	if (msg_size->physical_size == msg_size->virtual_size) {
--- a/src/lib-mail/message-send.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-mail/message-send.h	Tue Aug 27 22:16:54 2002 +0300
@@ -3,10 +3,10 @@
 
 #include "message-parser.h"
 
-/* Send message to client inserting CRs if needed. If max_virtual_size is
-   not negative, only that much of the message is sent (relative to
-   virtual_skip). Returns TRUE if successful. */
+/* Send message to client inserting CRs if needed. Only max_virtual_size
+   bytes if sent (relative to virtual_skip), if you want it unlimited,
+   use (uoff_t)-1. Returns TRUE if successful. */
 int message_send(IOBuffer *outbuf, IOBuffer *inbuf, MessageSize *msg_size,
-		 off_t virtual_skip, off_t max_virtual_size);
+		 uoff_t virtual_skip, uoff_t max_virtual_size);
 
 #endif
--- a/src/lib-mail/message-size.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-mail/message-size.c	Tue Aug 27 22:16:54 2002 +0300
@@ -58,7 +58,7 @@
 }
 
 void message_get_body_size(IOBuffer *inbuf, MessageSize *body,
-			   off_t max_virtual_size)
+			   uoff_t max_virtual_size)
 {
 	unsigned char *msg;
 	unsigned int i, size, startpos, missing_cr_count;
@@ -107,7 +107,7 @@
 	i_assert(body->virtual_size >= body->physical_size);
 }
 
-void message_skip_virtual(IOBuffer *inbuf, off_t virtual_skip,
+void message_skip_virtual(IOBuffer *inbuf, uoff_t virtual_skip,
 			  MessageSize *msg_size, int *cr_skipped)
 {
 	unsigned char *msg;
--- a/src/lib-mail/message-size.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-mail/message-size.h	Tue Aug 27 22:16:54 2002 +0300
@@ -6,15 +6,15 @@
 /* Calculate size of message header. Leave the inbuf point to first
    character in body. */
 void message_get_header_size(IOBuffer *inbuf, MessageSize *hdr);
-/* Calculate size of message body. Read only max_virtual_size virtual bytes
-   if it's >= 0. */
+/* Calculate size of message body. Read only max_virtual_size virtual bytes,
+   if you want it unlimited, use (uoff_t)-1. */
 void message_get_body_size(IOBuffer *inbuf, MessageSize *body,
-			   off_t max_virtual_size);
+			   uoff_t max_virtual_size);
 
 /* Skip number of virtual bytes from buffer. If first character is \n, and
    cr_skipped is FALSE, \r must be sent before it. msg_size is updated if
    it's not NULL. */
-void message_skip_virtual(IOBuffer *inbuf, off_t virtual_skip,
+void message_skip_virtual(IOBuffer *inbuf, uoff_t virtual_skip,
 			  MessageSize *msg_size, int *cr_skipped);
 
 /* Sum contents of src into dest. */
--- a/src/lib-storage/flags-file/flags-file.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-storage/flags-file/flags-file.c	Tue Aug 27 22:16:54 2002 +0300
@@ -80,7 +80,8 @@
 static void flags_file_sync(FlagsFile *ff)
 {
 	char *data, *data_end, *line;
-	int i, num;
+	unsigned int num;
+	int i;
 
 	memcpy(ff->sync_counter, ff->mmap_base, COUNTER_SIZE);
 
@@ -110,12 +111,12 @@
 			continue;
 
 		num = 0;
-		while (data != data_end && i_isdigit(*data)) {
-			num = num*10 + *data-'0';
+		while (data != data_end && *data >= '0' && *data <= '9') {
+			num = num*10 + (*data-'0');
 			data++;
 		}
 
-		if (num >= 0 && num < MAIL_CUSTOM_FLAGS_COUNT) {
+		if (num < MAIL_CUSTOM_FLAGS_COUNT) {
 			/* get the name */
 			if (data == data_end || *data != ' ')
 				continue;
@@ -334,10 +335,11 @@
 	return TRUE;
 }
 
-static int flags_file_remove(FlagsFile *ff, int idx)
+static int flags_file_remove(FlagsFile *ff, unsigned int idx)
 {
 	char *data, *data_end, *line;
-	int num, pos, linelen;
+	unsigned int num;
+	int pos, linelen;
 
 	data = ff->mmap_base;
 	data_end = data + ff->mmap_length;
@@ -354,8 +356,8 @@
 		line = ++data;
 
 		num = 0;
-		while (data != data_end && i_isdigit(*data)) {
-			num = num*10 + *data-'0';
+		while (data != data_end && *data >= '0' && *data <= '9') {
+			num = num*10 + (*data-'0');
 			data++;
 		}
 
@@ -397,7 +399,7 @@
 
 static void remove_unused_custom_flags(FlagsFile *ff, MailFlags used_flags)
 {
-	int i;
+	unsigned int i;
 
 	for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) {
 		if ((used_flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT))) == 0) {
--- a/src/lib-storage/index/index-fetch-section.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-storage/index/index-fetch-section.c	Tue Aug 27 22:16:54 2002 +0300
@@ -234,13 +234,13 @@
 
 	i_assert(len <= size->virtual_size);
 
-	if ((off_t)len <= sect->skip)
+	if (len <= sect->skip)
 		len = 0;
 	else {
 		dest += sect->skip;
 		len -= sect->skip;
 
-		if (sect->max_size >= 0 && (off_t)len > sect->max_size)
+		if (len > sect->max_size)
 			len = sect->max_size;
 	}
 
@@ -272,7 +272,7 @@
 {
 	MessagePart *part;
 	const char *path;
-	int num;
+	unsigned int num;
 
 	part = imap_msgcache_get_parts(ctx->cache, rec->uid);
 
@@ -283,7 +283,7 @@
 		while (*path != '\0' && *path != '.') {
 			if (*path < '0' || *path > '9')
 				return NULL;
-			num = num*10 + *path - '0';
+			num = num*10 + (*path - '0');
 			path++;
 		}
 
@@ -312,14 +312,13 @@
 {
 	IOBuffer *inbuf;
 	const char *str;
-	off_t skip_pos;
+	uoff_t skip_pos;
 
 	if (!imap_msgcache_get_data(ctx->cache, uid, &inbuf))
 		return FALSE;
 
 	/* jump to beginning of wanted data */
-	skip_pos = (off_t) (part->pos.physical_pos +
-			    part->header_size.physical_size);
+	skip_pos = part->pos.physical_pos + part->header_size.physical_size;
 	io_buffer_skip(inbuf, skip_pos);
 
 	str = t_strdup_printf("{%lu}\r\n",
--- a/src/lib-storage/index/index-fetch.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-storage/index/index-fetch.c	Tue Aug 27 22:16:54 2002 +0300
@@ -106,7 +106,7 @@
 
 	body_size.physical_size += hdr_size.physical_size;
 	body_size.virtual_size += hdr_size.virtual_size;
-	(void)message_send(ctx->outbuf, inbuf, &body_size, 0, -1);
+	(void)message_send(ctx->outbuf, inbuf, &body_size, 0, (uoff_t)-1);
 }
 
 static void index_fetch_rfc822_header(MailIndexRecord *rec, FetchContext *ctx)
@@ -125,7 +125,7 @@
 	str = t_strdup_printf(" RFC822.HEADER {%lu}\r\n",
 			      (unsigned long) hdr_size.virtual_size);
 	(void)io_buffer_send(ctx->outbuf, str, strlen(str));
-	(void)message_send(ctx->outbuf, inbuf, &hdr_size, 0, -1);
+	(void)message_send(ctx->outbuf, inbuf, &hdr_size, 0, (uoff_t)-1);
 }
 
 static void index_fetch_rfc822_text(MailIndexRecord *rec, FetchContext *ctx)
@@ -144,7 +144,7 @@
 	str = t_strdup_printf(" RFC822.TEXT {%lu}\r\n",
 			      (unsigned long) body_size.virtual_size);
 	(void)io_buffer_send(ctx->outbuf, str, strlen(str));
-	(void)message_send(ctx->outbuf, inbuf, &body_size, 0, -1);
+	(void)message_send(ctx->outbuf, inbuf, &body_size, 0, (uoff_t)-1);
 }
 
 static ImapCacheField index_get_cache(MailFetchData *fetch_data)
--- a/src/lib-storage/index/index-save.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-storage/index/index-save.c	Tue Aug 27 22:16:54 2002 +0300
@@ -11,15 +11,17 @@
 static int write_with_crlf(int fd, const unsigned char *data,
 			   unsigned int size, unsigned int *last_cr)
 {
-	unsigned int i, cr;
+	int i, cr;
+
+	i_assert(size < INT_MAX);
 
 	cr = *last_cr ? -1 : -2;
-	for (i = 0; i < size; i++) {
+	for (i = 0; i < (int)size; i++) {
 		if (data[i] == '\r')
 			cr = i;
 		else if (data[i] == '\n' && cr != i-1) {
 			/* missing CR */
-			if (write_full(fd, data, i) < 0)
+			if (write_full(fd, data, (unsigned int) i) < 0)
 				return FALSE;
 			if (write_full(fd, "\r", 1) < 0)
 				return FALSE;
--- a/src/lib-storage/index/index-search.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-storage/index/index-search.c	Tue Aug 27 22:16:54 2002 +0300
@@ -98,18 +98,16 @@
 	return FALSE;
 }
 
-static off_t str_to_off_t(const char *str)
+static uoff_t str_to_uoff_t(const char *str)
 {
-	off_t num;
+	uoff_t num;
 
 	num = 0;
 	while (*str != '\0') {
 		if (*str < '0' || *str > '9')
-			return -1;
+			return 0;
 
-		/* FIXME: this may overflow, and ANSI-C says overflowing
-		   signed values have undefined behaviour.. */
-		num = num*10 + *str - '0';
+		num = num*10 + (*str - '0');
 	}
 
 	return num;
@@ -180,9 +178,9 @@
 
 	/* sizes */
 	case SEARCH_SMALLER:
-		return rec->full_virtual_size < str_to_off_t(value);
+		return rec->full_virtual_size < str_to_uoff_t(value);
 	case SEARCH_LARGER:
-		return rec->full_virtual_size > str_to_off_t(value);
+		return rec->full_virtual_size > str_to_uoff_t(value);
 
 	default:
 		return -1;
@@ -505,7 +503,7 @@
 	}
 
 	if (have_text || have_body) {
-		if (inbuf->offset != (off_t)rec->header_size) {
+		if (inbuf->offset != rec->header_size) {
 			/* skip over headers */
 			i_assert(inbuf->offset == 0);
 			io_buffer_skip(inbuf, rec->header_size);
--- a/src/lib-storage/mail-storage.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib-storage/mail-storage.h	Tue Aug 27 22:16:54 2002 +0300
@@ -208,7 +208,8 @@
 	MailFetchBodyData *next;
 
 	const char *section; /* NOTE: always uppercased */
-	off_t skip, max_size; /* max_size is ignored if it's < 0 */
+	uoff_t skip, max_size; /* if you don't want max_size,
+	                          set it to (uoff_t)-1 */
 	unsigned int skip_set:1;
 	unsigned int peek:1;
 };
--- a/src/lib/iobuffer.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib/iobuffer.c	Tue Aug 27 22:16:54 2002 +0300
@@ -65,9 +65,10 @@
 }
 
 IOBuffer *io_buffer_create_mmap(int fd, Pool pool, unsigned int block_size,
-				off_t size)
+				uoff_t size)
 {
 	IOBuffer *buf;
+	off_t start_offset, stop_offset;
 
 	/* block size must be page aligned, and at least two pages long */
 	if (mmap_pagesize == 0) {
@@ -87,15 +88,19 @@
 	buf->receive = TRUE;
 
 	/* set offsets */
-	buf->start_offset = lseek(fd, 0, SEEK_CUR);
-	buf->size = size > 0 ? size :
-		lseek(fd, 0, SEEK_END) - buf->start_offset;
+	start_offset = lseek(fd, 0, SEEK_CUR);
+	stop_offset = lseek(fd, 0, SEEK_END);
 
-	if (buf->start_offset < 0 || buf->size < 0) {
+	if (start_offset < 0 || stop_offset < 0) {
 		i_error("io_buffer_create_mmap(): lseek() failed: %m");
 		buf->start_offset = buf->size = 0;
 	}
 
+	buf->start_offset = start_offset;
+	buf->size = size > 0 ? size :
+		start_offset > stop_offset ? 0 :
+		stop_offset - start_offset;
+
 	buf->skip = buf->pos = buf->start_offset;
 	return buf;
 }
@@ -555,7 +560,7 @@
 		return -1;
 
 	outbuf->offset += ret;
-	io_buffer_skip(inbuf, ret);
+	io_buffer_skip(inbuf, (unsigned int)ret);
 	if ((unsigned int) ret == size) {
 		/* all sent */
 		return 1;
@@ -595,12 +600,13 @@
 	buf->flush_context = context;
 }
 
-int io_buffer_read_mmaped(IOBuffer *buf, unsigned int size)
+static int io_buffer_read_mmaped(IOBuffer *buf, unsigned int size)
 {
-	off_t stop_offset, aligned_skip;
+	uoff_t stop_offset;
+	unsigned int aligned_skip;
 
-	stop_offset = buf->size + buf->start_offset;
-	if (stop_offset - buf->mmap_offset <= (off_t)buf->buffer_size) {
+	stop_offset = buf->start_offset + buf->size;
+	if (stop_offset - buf->mmap_offset <= buf->buffer_size) {
 		/* end of file is already mapped */
 		return -1;
 	}
@@ -694,7 +700,7 @@
         return io_buffer_read_max(buf, UINT_MAX);
 }
 
-void io_buffer_skip(IOBuffer *buf, unsigned int size)
+void io_buffer_skip(IOBuffer *buf, uoff_t size)
 {
 	int ret;
 
@@ -723,15 +729,13 @@
 			size -= ret;
 		}
 
-		(void)io_buffer_read_max(buf, size);
+		(void)io_buffer_read_max(buf, (unsigned int)size);
 	}
 }
 
-int io_buffer_seek(IOBuffer *buf, off_t offset)
+int io_buffer_seek(IOBuffer *buf, uoff_t offset)
 {
-	off_t real_offset;
-
-	i_assert(offset >= 0);
+	uoff_t real_offset;
 
 	if (buf->mmaped) {
 		/* first reset everything */
@@ -743,7 +747,13 @@
 		buf->pos = buf->skip = offset;
 	} else {
 		real_offset = buf->start_offset + offset;
-		if (lseek(buf->fd, real_offset, SEEK_SET) != real_offset)
+		if (real_offset > OFF_T_MAX) {
+			errno = EINVAL;
+			return FALSE;
+		}
+
+		if (lseek(buf->fd, (off_t)real_offset, SEEK_SET) !=
+		    (off_t)real_offset)
 			return FALSE;
 	}
 
--- a/src/lib/iobuffer.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib/iobuffer.h	Tue Aug 27 22:16:54 2002 +0300
@@ -10,8 +10,8 @@
 struct _IOBuffer {
 	int fd;
 
-	off_t start_offset;
-	off_t offset, size; /* virtual offset, 0 = start_offset */
+	uoff_t start_offset;
+	uoff_t offset, size; /* virtual offset, 0 = start_offset */
 
 /* private: */
 	Pool pool;
@@ -53,7 +53,7 @@
 /* Read the file by mmap()ing it in blocks. stop_offset specifies where to
    stop reading, or 0 to end of file. */
 IOBuffer *io_buffer_create_mmap(int fd, Pool pool, unsigned int block_size,
-				off_t size);
+				uoff_t size);
 /* Destroy a buffer. */
 void io_buffer_destroy(IOBuffer *buf);
 /* Mark the buffer closed. Any sends/reads after this will return -1.
@@ -102,10 +102,10 @@
 /* Like io_buffer_read(), but don't read more than specified size. */
 int io_buffer_read_max(IOBuffer *buf, unsigned int size);
 /* Skip forward a number of bytes */
-void io_buffer_skip(IOBuffer *buf, unsigned int size);
+void io_buffer_skip(IOBuffer *buf, uoff_t size);
 /* Seek to specified position from beginning of file. This works only for
    files. Returns TRUE if successful. */
-int io_buffer_seek(IOBuffer *buf, off_t offset);
+int io_buffer_seek(IOBuffer *buf, uoff_t offset);
 /* Returns the next line from input buffer, or NULL if more data is needed
    to make a full line. NOTE: call to io_buffer_read() invalidates the
    returned data. */
--- a/src/lib/lib.h	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib/lib.h	Tue Aug 27 22:16:54 2002 +0300
@@ -19,6 +19,17 @@
 #ifdef HAVE_CONFIG_H
 #  include "../../config.h"
 #endif
+
+#if defined (UOFF_T_INT)
+typedef unsigned int uoff_t;
+#elif defined (UOFF_T_LONG)
+typedef unsigned long uoff_t;
+#elif defined (UOFF_T_LONG_LONG)
+typedef unsigned long long uoff_t;
+#else
+#  error uoff_t size not set
+#endif
+
 #include "compat.h"
 #include "macros.h"
 #include "failures.h"
--- a/src/lib/strfuncs.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib/strfuncs.c	Tue Aug 27 22:16:54 2002 +0300
@@ -164,7 +164,7 @@
                   while (c >= '0' && c <= '9')
                     {
                       format++;
-                      v_uint = v_uint * 10 + c - '0';
+                      v_uint = v_uint * 10 + (c - '0');
                       c = *format;
                     }
                   if (spec.seen_precision)
--- a/src/lib/temp-string.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/lib/temp-string.c	Tue Aug 27 22:16:54 2002 +0300
@@ -54,8 +54,14 @@
 	RealTempString *rstr = (RealTempString *) tstr;
 	char *str;
 
-	if (rstr->len + size + 1 > rstr->alloc_size) {
-                rstr->alloc_size = nearest_power(rstr->len + size + 1);
+	size += rstr->len + 1;
+	if (size <= rstr->len || size > INT_MAX) {
+		/* overflow */
+		i_panic("t_string_inc(): Out of memory for %u bytes", size);
+	}
+
+	if (size > rstr->alloc_size) {
+                rstr->alloc_size = nearest_power(size);
 
 		if (!t_try_grow(rstr->str, rstr->alloc_size)) {
 			str = t_malloc(rstr->alloc_size);
--- a/src/master/main.c	Tue Aug 27 20:35:00 2002 +0300
+++ b/src/master/main.c	Tue Aug 27 22:16:54 2002 +0300
@@ -154,7 +154,7 @@
 	}
 }
 
-static void main_init()
+static void main_init(void)
 {
 	lib_init_signals(sig_quit);