[dovecot-cvs] dovecot/src/lib-index mail-cache.c,1.8,1.9

cras at procontrol.fi cras at procontrol.fi
Fri Sep 5 02:56:50 EEST 2003


Update of /home/cvs/dovecot/src/lib-index
In directory danu:/tmp/cvs-serv17200/lib-index

Modified Files:
	mail-cache.c 
Log Message:
Include used-bit for all bytes in offsets to make sure their reads aren't only partial



Index: mail-cache.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/mail-cache.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- mail-cache.c	2 Sep 2003 22:33:33 -0000	1.8
+++ mail-cache.c	4 Sep 2003 22:56:48 -0000	1.9
@@ -137,6 +137,34 @@
 mail_cache_lookup(struct mail_cache *cache,
 		  const struct mail_index_record *rec);
 
+static uint32_t uint32_to_offset(uint32_t offset)
+{
+	unsigned char buf[4];
+
+	i_assert(offset < 0x40000000);
+	i_assert((offset & 3) == 0);
+
+	offset >>= 2;
+	buf[0] = 0x80 | ((offset & 0x0fe00000) >> 21);
+	buf[1] = 0x80 | ((offset & 0x001fc000) >> 14);
+	buf[2] = 0x80 | ((offset & 0x00003f80) >> 7);
+	buf[3] = 0x80 |  (offset & 0x0000007f);
+	return *((uint32_t *) buf);
+}
+
+static uint32_t offset_to_uint32(uint32_t offset)
+{
+	const unsigned char *buf = (const unsigned char *) &offset;
+
+	if ((offset & 0x80808080) != 0x80808080)
+		return 0;
+
+	return (((uint32_t)buf[3] & 0x7f) << 2) |
+		(((uint32_t)buf[2] & 0x7f) << 9) |
+		(((uint32_t)buf[1] & 0x7f) << 16) |
+		(((uint32_t)buf[0] & 0x7f) << 23);
+}
+
 static int mail_cache_set_syscall_error(struct mail_cache *cache,
 					const char *function)
 {
@@ -602,7 +630,7 @@
 	if (str == NULL)
 		header_idx = -1;
 	else {
-		hdr->header_offsets[0] = uint32_to_nbo(offset | 2);
+		hdr->header_offsets[0] = uint32_to_offset(offset);
 		header_idx = i;
 
 		size = strlen(str) + 1;
@@ -620,13 +648,13 @@
 		cache_rec = mail_cache_lookup(cache, rec);
 		if (cache_rec == NULL)
 			rec->cache_offset = 0;
-		else if ((nbo_to_uint32(cache_rec->next_offset) & 2) == 0) {
+		else if (offset_to_uint32(cache_rec->next_offset) == 0) {
 			/* just one unmodified block, copy it */
 			size = nbo_to_uint32(cache_rec->size);
 			i_assert(offset + size <= new_file_size);
 
 			memcpy(mmap_base + offset, cache_rec, size);
-			rec->cache_offset = uint32_to_nbo(offset | 2);
+			rec->cache_offset = uint32_to_offset(offset);
 
 			size = (size + 3) & ~3;
 			offset += size;
@@ -641,7 +669,7 @@
 			used_fields |= cache_rec->fields;
 			t_pop();
 
-			rec->cache_offset = uint32_to_nbo(offset | 2);
+			rec->cache_offset = uint32_to_offset(offset);
 			offset += size;
 		}
 
@@ -893,38 +921,29 @@
 
 static void mark_update(buffer_t **buf, uint32_t offset, uint32_t data)
 {
-	unsigned char lower_data;
-
 	if (*buf == NULL)
 		*buf = buffer_create_dynamic(system_pool, 1024, (size_t)-1);
 
 	/* data is in big endian, we want to update only the lowest byte */
-	offset += sizeof(uint32_t) - 1;
 	buffer_append(*buf, &offset, sizeof(offset));
-
-	lower_data = data & 0xff;
-	buffer_append(*buf, &lower_data, 1);
+	buffer_append(*buf, &data, sizeof(data));
 }
 
 static int write_mark_updates(struct mail_index *index, buffer_t *marks,
 			      const char *path, int fd)
 {
-	const unsigned char *data, *end;
-	uint32_t offset;
+	const uint32_t *data, *end;
 	size_t size;
 
 	data = buffer_get_data(marks, &size);
-	end = data + size;
+	end = data + size/sizeof(uint32_t);
 
 	while (data < end) {
-		memcpy(&offset, data, sizeof(offset));
-		data += sizeof(offset);
-
-		if (pwrite(fd, data, sizeof(*data), offset) < 0) {
+		if (pwrite(fd, data+1, sizeof(*data), data[0]) < 0) {
 			index_file_set_syscall_error(index, path, "pwrite()");
 			return FALSE;
 		}
-		data++;
+		data += 2;
 	}
 	return TRUE;
 }
@@ -943,9 +962,9 @@
 		memcpy(&offset, data, sizeof(offset));
 		data += sizeof(offset);
 
-		i_assert(offset < mmap_length);
-		((char *) mmap_base)[offset] = *data;
-		data++;
+		i_assert(offset <= mmap_length - sizeof(uint32_t));
+		memcpy((char *) mmap_base + offset, data, sizeof(uint32_t));
+		data += sizeof(uint32_t);
 	}
 }
 
@@ -1048,10 +1067,18 @@
 
 int mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
 {
+	struct mail_cache *cache = ctx->cache;
+	unsigned int i;
+
 	/* no need to actually modify the file - we just didn't update
 	   used_file_size */
-	ctx->cache->used_file_size =
-		nbo_to_uint32(ctx->cache->header->used_file_size);
+	cache->used_file_size = nbo_to_uint32(cache->header->used_file_size);
+
+	/* make sure we don't cache the headers */
+	for (i = 0; i < ctx->next_unused_header_lowwater; i++) {
+		if (offset_to_uint32(cache->header->header_offsets[i]) == 0)
+			cache->split_offsets[i] = 1;
+	}
 
 	mail_cache_transaction_flush(ctx);
 	return TRUE;
@@ -1114,9 +1141,15 @@
 	/* NOTE: must be done within transaction or rollback would break it */
 	uint32_t offset;
 
-	i_assert((size % sizeof(uint32_t)) == 0);
+	i_assert((size & 3) == 0);
 
 	offset = ctx->cache->used_file_size;
+	if (offset >= 0x40000000) {
+		index_set_error(ctx->cache->index, "Cache file too large: %s",
+				ctx->cache->filepath);
+		return 0;
+	}
+
 	if (offset + size > ctx->cache->mmap_length) {
 		if (!mail_cache_grow(ctx->cache, size))
 			return 0;
@@ -1132,13 +1165,10 @@
 	uint32_t offset, data_size;
 	unsigned char *buf;
 
-	offset = nbo_to_uint32(cache->header->header_offsets[idx]);
+	offset = offset_to_uint32(cache->header->header_offsets[idx]);
 
-	if ((offset & 2) == 0 &&
-	    (cache->trans_ctx == NULL ||
-	     cache->trans_ctx->next_unused_header_lowwater <= idx))
+	if (offset == 0)
 		return NULL;
-	offset &= ~2;
 
 	if (!mmap_update(cache, offset, 1024))
 		return NULL;
@@ -1236,7 +1266,7 @@
 
 	i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
 	i_assert(idx >= ctx->next_unused_header_lowwater);
-	i_assert((nbo_to_uint32(cache->header->header_offsets[idx]) & 2) == 0);
+	i_assert(offset_to_uint32(cache->header->header_offsets[idx]) == 0);
 
 	t_push();
 
@@ -1264,19 +1294,18 @@
 		memcpy((char *) cache->mmap_base + offset,
 		       &size, sizeof(uint32_t));
 
-		cache->header->header_offsets[idx] = uint32_to_nbo(offset);
-
-		/* the above value may actually be in split_offsets[] if
-		   last transaction was rolled back. make sure the next
-		   get_header_fields() notices it's changed */
-                cache->split_offsets[idx] = 0;
+		/* update cached headers */
+		cache->split_offsets[idx] = cache->header->header_offsets[idx];
+		cache->split_headers[idx] =
+			split_header(cache, buffer_get_data(buffer, NULL));
 
 		/* mark used-bit to be updated later. not really needed for
 		   read-safety, but if transaction get rolled back we can't let
 		   this point to invalid location. */
 		update_offset = (char *) &cache->header->header_offsets[idx] -
 			(char *) cache->mmap_base;
-		mark_update(&ctx->cache_marks, update_offset, offset | 2);
+		mark_update(&ctx->cache_marks, update_offset,
+			    uint32_to_offset(offset));
 
 		/* make sure get_header_fields() still works for this header
 		   while the transaction isn't yet committed. */
@@ -1293,15 +1322,9 @@
 	struct mail_cache_record *cache_rec;
 	size_t size;
 
-	offset = nbo_to_uint32(offset);
-
-	if ((offset & 1) != 0) {
-		mail_cache_set_corrupted(cache, "bit 0 set in data offset");
-		return NULL;
-	}
-	if ((offset & 2) == 0)
+	offset = offset_to_uint32(offset);
+	if (offset == 0)
 		return NULL;
-	offset &= ~2;
 
 	if (!mmap_update(cache, offset, sizeof(*cache_rec) + 1024))
 		return NULL;
@@ -1366,24 +1389,21 @@
 		/* first cache record - update offset in index file */
 		i_assert(cache->index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
-		rec->cache_offset = uint32_to_nbo(write_offset);
-
-		/* mark used-bit to be updated later */
+		/* mark cache_offset to be updated later */
 		update_offset = (char *) &rec->cache_offset -
 			(char *) cache->index->mmap_base;
-		mark_update(&ctx->index_marks, update_offset, write_offset | 2);
+		mark_update(&ctx->index_marks, update_offset,
+			    uint32_to_offset(write_offset));
 	} else {
 		/* find the last cache record */
 		while ((next = cache_get_next_record(cache, cache_rec)) != NULL)
 			cache_rec = next;
 
-		/* set our offset, keep the used-bit still unset */
-		cache_rec->next_offset = uint32_to_nbo(write_offset);
-
-		/* mark used-bit to be updated later */
+		/* mark next_offset to be updated later */
 		update_offset = (char *) &cache_rec->next_offset -
 			(char *) cache->mmap_base;
-		mark_update(&ctx->cache_marks, update_offset, write_offset | 2);
+		mark_update(&ctx->cache_marks, update_offset,
+			    uint32_to_offset(write_offset));
 	}
 
 	memcpy((char *) cache->mmap_base + write_offset,



More information about the dovecot-cvs mailing list