[dovecot-cvs]
dovecot/src/lib-mail message-part-serialize.c,1.16,1.17
cras at procontrol.fi
cras at procontrol.fi
Thu Aug 21 05:41:13 EEST 2003
Update of /home/cvs/dovecot/src/lib-mail
In directory danu:/tmp/cvs-serv13665/lib-mail
Modified Files:
message-part-serialize.c
Log Message:
Serialized message_parts are now packed into smaller space.
Index: message-part-serialize.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-mail/message-part-serialize.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- message-part-serialize.c 15 May 2003 19:22:22 -0000 1.16
+++ message-part-serialize.c 21 Aug 2003 01:41:11 -0000 1.17
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
#include "lib.h"
#include "buffer.h"
@@ -6,38 +6,34 @@
#include "message-part-serialize.h"
/*
- Serialized a series of SerializedMessageParts:
-
root part
root's first children
children's first children
...
root's next children
...
-*/
-/* struct is 8 byte aligned */
-struct serialized_message_part {
- uoff_t physical_pos;
-
- uoff_t header_physical_size;
- uoff_t header_virtual_size;
-
- uoff_t body_physical_size;
- uoff_t body_virtual_size;
+ part
+ unsigned int flags
+ (not root part)
+ uoff_t physical_pos
+ uoff_t header_physical_size
+ uoff_t header_virtual_size
+ uoff_t body_physical_size
+ uoff_t body_virtual_size
+ (flags & (MESSAGE_PART_FLAG_TEXT | MESSAGE_PART_FLAG_MESSAGE_RFC822))
+ unsigned int body_lines
+ (flags & (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_MESSAGE_RFC822))
+ unsigned int children_count
- unsigned int header_lines;
- unsigned int body_lines;
+*/
- unsigned int children_count;
- unsigned int flags;
-};
+#define MINIMUM_SERIALIZED_SIZE \
+ (sizeof(unsigned int) + sizeof(uoff_t) * 4)
struct deserialize_context {
pool_t pool;
-
- const struct serialized_message_part *spart;
- unsigned int sparts_left;
+ const unsigned char *data, *end;
uoff_t pos;
const char *error;
@@ -46,39 +42,53 @@
static unsigned int
_message_part_serialize(struct message_part *part, buffer_t *dest)
{
- struct serialized_message_part spart, *spart_p;
unsigned int count, children_count;
- size_t pos;
+ size_t children_offset;
+ int root = part->parent == NULL;
count = 0;
while (part != NULL) {
/* create serialized part */
- memset(&spart, 0, sizeof(spart));
-
- spart.physical_pos = part->physical_pos;
-
- spart.header_physical_size = part->header_size.physical_size;
- spart.header_virtual_size = part->header_size.virtual_size;
- spart.header_lines = part->header_size.lines;
+ buffer_append(dest, &part->flags, sizeof(part->flags));
+ if (root)
+ root = FALSE;
+ else {
+ buffer_append(dest, &part->physical_pos,
+ sizeof(part->physical_pos));
+ }
+ buffer_append(dest, &part->header_size.physical_size,
+ sizeof(part->header_size.physical_size));
+ buffer_append(dest, &part->header_size.virtual_size,
+ sizeof(part->header_size.virtual_size));
+ buffer_append(dest, &part->body_size.physical_size,
+ sizeof(part->body_size.physical_size));
+ buffer_append(dest, &part->body_size.virtual_size,
+ sizeof(part->body_size.virtual_size));
- spart.body_physical_size = part->body_size.physical_size;
- spart.body_virtual_size = part->body_size.virtual_size;
- spart.body_lines = part->body_size.lines;
+ if ((part->flags & (MESSAGE_PART_FLAG_TEXT |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0) {
+ buffer_append(dest, &part->body_size.lines,
+ sizeof(part->body_size.lines));
+ }
- spart.flags = part->flags;
+ if ((part->flags & (MESSAGE_PART_FLAG_MULTIPART |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0) {
+ children_offset = buffer_get_used_size(dest);
+ children_count = 0;
+ buffer_append(dest, &children_count,
+ sizeof(children_count));
- buffer_append(dest, &spart, sizeof(spart));
- if (part->children != NULL) {
- pos = buffer_get_used_size(dest) - sizeof(spart);
- children_count =
- _message_part_serialize(part->children, dest);
+ if (part->children != NULL) {
+ children_count =
+ _message_part_serialize(part->children,
+ dest);
- /* note that we can't just save the pointer to
- our appended spart since it may change after
- child-appends have realloc()ed buffer memory. */
- spart_p = buffer_get_space_unsafe(dest, pos,
- sizeof(spart));
- spart_p->children_count = children_count;
+ buffer_write(dest, children_offset,
+ &children_count,
+ sizeof(children_count));
+ }
+ } else {
+ i_assert(part->children == NULL);
}
count++;
@@ -93,88 +103,132 @@
_message_part_serialize(part, dest);
}
+static int read_next(struct deserialize_context *ctx,
+ void *buffer, size_t buffer_size)
+{
+ if (ctx->data + buffer_size > ctx->end) {
+ ctx->error = "Not enough data";
+ return FALSE;
+ }
+
+ memcpy(buffer, ctx->data, buffer_size);
+ ctx->data += buffer_size;
+ return TRUE;
+}
+
static int message_part_deserialize_part(struct deserialize_context *ctx,
struct message_part *parent,
- unsigned int child_count,
+ unsigned int siblings,
struct message_part **part_r)
{
- const struct serialized_message_part *spart;
struct message_part *part, *first_part, **next_part;
+ unsigned int children_count;
uoff_t pos;
+ int root = parent == NULL;
first_part = NULL;
next_part = NULL;
- while (child_count > 0) {
- child_count--;
- if (ctx->sparts_left == 0) {
- ctx->error = "Not enough data for all parts";
- return FALSE;
- }
-
- spart = ctx->spart;
- ctx->spart++;
- ctx->sparts_left--;
+ while (siblings > 0) {
+ siblings--;
part = p_new(ctx->pool, struct message_part, 1);
- part->physical_pos = spart->physical_pos;
+ part->parent = parent;
+
+ if (!read_next(ctx, &part->flags, sizeof(part->flags)))
+ return FALSE;
+
+ if (root)
+ root = FALSE;
+ else {
+ if (!read_next(ctx, &part->physical_pos,
+ sizeof(part->physical_pos)))
+ return FALSE;
+ }
if (part->physical_pos < ctx->pos) {
ctx->error = "physical_pos less than expected";
return FALSE;
}
- part->header_size.physical_size = spart->header_physical_size;
- part->header_size.virtual_size = spart->header_virtual_size;
- part->header_size.lines = spart->header_lines;
-
- if (spart->header_virtual_size < spart->header_physical_size) {
- ctx->error = "header_virtual_size too small";
+ if (!read_next(ctx, &part->header_size.physical_size,
+ sizeof(part->header_size.physical_size)))
return FALSE;
- }
- part->body_size.physical_size = spart->body_physical_size;
- part->body_size.virtual_size = spart->body_virtual_size;
- part->body_size.lines = spart->body_lines;
+ if (!read_next(ctx, &part->header_size.virtual_size,
+ sizeof(part->header_size.virtual_size)))
+ return FALSE;
- if (spart->body_virtual_size < spart->body_physical_size) {
- ctx->error = "body_virtual_size too small";
+ if (part->header_size.virtual_size <
+ part->header_size.physical_size) {
+ ctx->error = "header_size.virtual_size too small";
return FALSE;
}
- part->flags = spart->flags;
- part->parent = parent;
-
- /* our children must be after our physical_pos and the last
- child must be within our size. */
- ctx->pos = part->physical_pos;
- pos = part->physical_pos + spart->header_physical_size +
- spart->body_physical_size;
+ if (!read_next(ctx, &part->body_size.physical_size,
+ sizeof(part->body_size.physical_size)))
+ return FALSE;
- if (!message_part_deserialize_part(ctx, part,
- spart->children_count,
- &part->children))
+ if (!read_next(ctx, &part->body_size.virtual_size,
+ sizeof(part->body_size.virtual_size)))
return FALSE;
- if (ctx->pos > pos) {
- ctx->error = "child part location exceeds our size";
+ if ((part->flags & (MESSAGE_PART_FLAG_TEXT |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0) {
+ if (!read_next(ctx, &part->body_size.lines,
+ sizeof(part->body_size.lines)))
+ return FALSE;
+ }
+
+ if (part->body_size.virtual_size <
+ part->body_size.physical_size) {
+ ctx->error = "body_size.virtual_size too small";
return FALSE;
}
- ctx->pos = pos; /* save it for above check for parent */
+
+ if ((part->flags & (MESSAGE_PART_FLAG_MULTIPART |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0) {
+ if (!read_next(ctx, &children_count,
+ sizeof(children_count)))
+ return FALSE;
+ } else {
+ children_count = 0;
+ }
if (part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) {
/* Only one child is possible */
- if (part->children == NULL) {
+ if (children_count == 0) {
ctx->error =
"message/rfc822 part has no children";
return FALSE;
}
- if (part->children->next != NULL) {
+ if (children_count != 1) {
ctx->error = "message/rfc822 part "
"has multiple children";
return FALSE;
}
}
+ if (children_count > 0) {
+ /* our children must be after our physical_pos and
+ the last child must be within our size. */
+ ctx->pos = part->physical_pos;
+ pos = part->physical_pos +
+ part->header_size.physical_size +
+ part->body_size.physical_size;
+
+ if (!message_part_deserialize_part(ctx, part,
+ children_count,
+ &part->children))
+ return FALSE;
+
+ if (ctx->pos > pos) {
+ ctx->error =
+ "child part location exceeds our size";
+ return FALSE;
+ }
+ ctx->pos = pos; /* save it for above check for parent */
+ }
+
if (first_part == NULL)
first_part = part;
if (next_part != NULL)
@@ -186,47 +240,23 @@
return TRUE;
}
-static int check_size(size_t size, const char **error)
-{
- if (size < sizeof(struct serialized_message_part)) {
- *error = "Not enough data for root";
- return FALSE;
- }
-
- if ((size % sizeof(struct serialized_message_part)) != 0) {
- *error = "Incorrect data size";
- return FALSE;
- }
-
- if (size / sizeof(struct serialized_message_part) > UINT_MAX) {
- *error = "Insane amount of data";
- return FALSE;
- }
-
- return TRUE;
-}
-
struct message_part *message_part_deserialize(pool_t pool, const void *data,
size_t size, const char **error)
{
struct deserialize_context ctx;
struct message_part *part;
- if (!check_size(size, error))
- return NULL;
-
memset(&ctx, 0, sizeof(ctx));
ctx.pool = pool;
- ctx.spart = data;
- ctx.sparts_left =
- (unsigned int) (size / sizeof(struct serialized_message_part));
+ ctx.data = data;
+ ctx.end = ctx.data + size;
if (!message_part_deserialize_part(&ctx, NULL, 1, &part)) {
*error = ctx.error;
return NULL;
}
- if (ctx.sparts_left > 0) {
+ if (ctx.data != ctx.end) {
*error = "Too much data";
return NULL;
}
@@ -234,53 +264,80 @@
return part;
}
+static size_t get_serialized_size(unsigned int flags)
+{
+ size_t size = sizeof(unsigned int) + sizeof(uoff_t) * 5;
+
+ if ((flags & (MESSAGE_PART_FLAG_TEXT |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0)
+ size += sizeof(unsigned int);
+ if ((flags & (MESSAGE_PART_FLAG_MULTIPART |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) != 0)
+ size += sizeof(unsigned int);
+ return size;
+}
+
int message_part_serialize_update_header(void *data, size_t size,
struct message_size *hdr_size,
const char **error)
{
- struct serialized_message_part *spart = data;
- uoff_t first_pos;
+ unsigned char *buf = data;
+ size_t offset, part_size;
+ uoff_t uofft_size, old_size;
off_t pos_diff;
- unsigned int children, i, count;
+ unsigned int flags;
- if (!check_size(size, error))
- return FALSE;
+ i_assert(hdr_size->physical_size <= OFF_T_MAX);
- if (hdr_size->physical_size >= OFF_T_MAX ||
- spart->physical_pos >= OFF_T_MAX ||
- spart->header_physical_size >= OFF_T_MAX) {
- *error = "Invalid data";
+ if (size < MINIMUM_SERIALIZED_SIZE) {
+ *error = "Not enough data";
return FALSE;
}
- first_pos = spart->physical_pos;
- pos_diff = (off_t)hdr_size->physical_size - spart->header_physical_size;
+ memcpy(&flags, buf, sizeof(flags));
+ memcpy(&uofft_size, buf + sizeof(unsigned int), sizeof(uoff_t));
- spart->header_physical_size = hdr_size->physical_size;
- spart->header_virtual_size = hdr_size->virtual_size;
- spart->header_lines = hdr_size->lines;
+ if (uofft_size > OFF_T_MAX) {
+ *error = "Invalid physical_size";
+ return FALSE;
+ }
+ pos_diff = (off_t)hdr_size->physical_size - (off_t)uofft_size;
+ old_size = uofft_size;
+
+ memcpy(buf + sizeof(unsigned int),
+ &hdr_size->physical_size, sizeof(uoff_t));
+ memcpy(buf + sizeof(unsigned int) + sizeof(uoff_t),
+ &hdr_size->virtual_size, sizeof(uoff_t));
if (pos_diff != 0) {
- /* have to update all positions, but skip the first one */
- children = spart->children_count;
- count = (size / sizeof(struct serialized_message_part))-1;
- spart++;
+ /* have to update all positions, but skip the root */
+ offset = get_serialized_size(flags) - sizeof(uoff_t);
- for (i = 0; i < count; i++, spart++) {
- if (spart->physical_pos < first_pos ||
- spart->physical_pos >= OFF_T_MAX) {
+ while (offset + sizeof(unsigned int) < size) {
+ memcpy(buf + offset, &flags, sizeof(flags));
+
+ part_size = get_serialized_size(flags);
+ if (offset + part_size > size) {
+ *error = "Not enough data";
+ return FALSE;
+ }
+ memcpy(&uofft_size, buf + offset + sizeof(flags),
+ sizeof(uoff_t));
+
+ if (uofft_size < old_size || uofft_size >= OFF_T_MAX) {
/* invalid offset, might cause overflow */
*error = "Invalid offset";
return FALSE;
}
+ uofft_size += pos_diff;
- children += spart->children_count;
- spart->physical_pos += pos_diff;
+ memcpy(buf + offset + sizeof(flags), &uofft_size,
+ sizeof(uoff_t));
+ offset += part_size;
}
- if (children != count) {
- *error = t_strdup_printf("Size mismatch %u vs %u",
- children, count);
+ if (offset != size) {
+ *error = "Invalid size";
return FALSE;
}
}
@@ -292,19 +349,34 @@
struct message_size *hdr_size,
struct message_size *body_size)
{
- const struct serialized_message_part *spart = data;
+ const unsigned char *buf = data;
+ unsigned int flags;
/* make sure it looks valid */
- if (size < sizeof(struct serialized_message_part))
+ if (size < MINIMUM_SERIALIZED_SIZE)
return FALSE;
- hdr_size->physical_size = spart->header_physical_size;
- hdr_size->virtual_size = spart->header_virtual_size;
- hdr_size->lines = spart->header_lines;
+ memcpy(&flags, buf, sizeof(flags));
+ buf += sizeof(flags);
+ memcpy(&hdr_size->physical_size, buf, sizeof(uoff_t));
+ buf += sizeof(uoff_t);
+ memcpy(&hdr_size->virtual_size, buf, sizeof(uoff_t));
+ buf += sizeof(uoff_t);
+ hdr_size->lines = 0;
- body_size->physical_size = spart->body_physical_size;
- body_size->virtual_size = spart->body_virtual_size;
- body_size->lines = spart->body_lines;
+ memcpy(&body_size->physical_size, buf, sizeof(uoff_t));
+ buf += sizeof(uoff_t);
+ memcpy(&body_size->virtual_size, buf, sizeof(uoff_t));
+ buf += sizeof(uoff_t);
+
+ if ((flags & (MESSAGE_PART_FLAG_TEXT |
+ MESSAGE_PART_FLAG_MESSAGE_RFC822)) == 0)
+ body_size->lines = 0;
+ else {
+ if (size < MINIMUM_SERIALIZED_SIZE + sizeof(unsigned int))
+ return FALSE;
+ memcpy(&body_size->lines, buf, sizeof(unsigned int));
+ }
return TRUE;
}
More information about the dovecot-cvs
mailing list