]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
fixes
authorTimo Sirainen <tss@iki.fi>
Sat, 19 Jun 2004 00:19:48 +0000 (03:19 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 19 Jun 2004 00:19:48 +0000 (03:19 +0300)
--HG--
branch : HEAD

src/lib-storage/index/mbox/mbox-sync-private.h
src/lib-storage/index/mbox/mbox-sync-rewrite.c
src/lib-storage/index/mbox/mbox-sync-update.c
src/lib-storage/index/mbox/mbox-sync.c

index d93db049dddb2b080923e19ef4478e39c2c6d2e0..84b242e19532257568da8dbdbfa985ae1fefd9f2 100644 (file)
@@ -106,8 +106,8 @@ void mbox_sync_update_header(struct mbox_sync_mail_context *ctx,
 void mbox_sync_update_header_from(struct mbox_sync_mail_context *ctx,
                                  const struct mbox_sync_mail *mail);
 int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff);
-int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx,
-                     uint32_t first_seq, uint32_t last_seq, off_t extra_space);
+int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, uoff_t extra_space,
+                     uint32_t first_seq, uint32_t last_seq);
 
 int mbox_sync_seek(struct mbox_sync_context *sync_ctx, uoff_t from_offset);
 int mbox_move(struct mbox_sync_context *sync_ctx,
index 3fe32189309b139db57c8c92d25e92a37d140e45..c3b07c7adc4ab41dd353eb520b6c46f7a4c1495f 100644 (file)
@@ -49,6 +49,28 @@ int mbox_move(struct mbox_sync_context *sync_ctx,
        return (int)ret;
 }
 
+static int mbox_fill_space(struct mbox_sync_context *sync_ctx,
+                          uoff_t offset, uoff_t size)
+{
+       unsigned char space[1024];
+
+       memset(space, ' ', sizeof(space));
+       while (size > sizeof(space)) {
+               if (pwrite_full(sync_ctx->fd, space,
+                               sizeof(space), offset) < 0) {
+                       mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
+                       return -1;
+               }
+               size -= sizeof(space);
+       }
+
+       if (pwrite_full(sync_ctx->fd, space, size, offset) < 0) {
+               mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
+               return -1;
+       }
+       return 0;
+}
+
 static void mbox_sync_headers_add_space(struct mbox_sync_mail_context *ctx,
                                        size_t size)
 {
@@ -58,23 +80,11 @@ static void mbox_sync_headers_add_space(struct mbox_sync_mail_context *ctx,
 
        i_assert(size < SSIZE_T_MAX);
 
-       if (ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] == (size_t)-1 &&
-           size >= sizeof("X-Keywords: \n")-1) {
-               /* Add X-Keywords */
-               start_pos = str_len(ctx->header);
-               if (ctx->have_eoh)
-                       start_pos--;
-               ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = start_pos;
-
-               str_insert(ctx->header, start_pos, "X-Keywords: \n");
-               size -= sizeof("X-Keywords: \n")-1;
-       } else {
-               /* Append at the end of X-Keywords header,
-                  or X-UID if it doesn't exist */
-               start_pos = ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] != (size_t)-1 ?
-                       ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] :
-                       ctx->hdr_pos[MBOX_HDR_X_UID];
-       }
+       /* Append at the end of X-Keywords header,
+          or X-UID if it doesn't exist */
+       start_pos = ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] != (size_t)-1 ?
+               ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] :
+               ctx->hdr_pos[MBOX_HDR_X_UID];
 
        data = str_data(ctx->header);
        data_size = str_len(ctx->header);
@@ -90,8 +100,8 @@ static void mbox_sync_headers_add_space(struct mbox_sync_mail_context *ctx,
                }
        }
 
-       /* pos points to end of headers now, and start_pos to beginning of
-          whitespace. */
+       /* pos points to end of headers now, and start_pos to beginning
+          of whitespace. */
        buffer_copy(ctx->header, pos + size,
                    ctx->header, pos, (size_t)-1);
        p = buffer_get_space_unsafe(ctx->header, pos, size);
@@ -193,8 +203,9 @@ int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff)
        old_hdr_size = ctx->body_offset - ctx->hdr_offset;
        new_hdr_size = str_len(ctx->header);
 
-       /* do we have enough space? */
-       if (new_hdr_size < old_hdr_size) {
+       if (new_hdr_size <= old_hdr_size) {
+               /* add space. note that we must call add_space() even if we're
+                  not adding anything so mail.offset gets fixed. */
                mbox_sync_headers_add_space(ctx, old_hdr_size - new_hdr_size);
        } else if (new_hdr_size > old_hdr_size) {
                /* try removing the space where we can */
@@ -205,6 +216,8 @@ int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff)
                if (new_hdr_size <= old_hdr_size) {
                        /* good, we removed enough. */
                        i_assert(new_hdr_size == old_hdr_size);
+                       ctx->mail.space =
+                               -(ssize_t)(new_hdr_size - old_hdr_size);
                } else if (move_diff < 0 &&
                           new_hdr_size - old_hdr_size <= -move_diff) {
                        /* moving backwards - we can use the extra space from
@@ -256,12 +269,12 @@ int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff)
 static int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx,
                                   struct mbox_sync_mail *mails,
                                   uint32_t seq, uint32_t idx,
-                                  uint32_t extra_per_mail,
-                                  uoff_t *end_offset)
+                                  uoff_t space_diff, uoff_t end_offset)
 {
        struct mbox_sync_mail_context mail_ctx;
        uint32_t old_prev_msg_uid;
-       uoff_t offset;
+       uoff_t hdr_offset, offset, dest_offset;
+       size_t old_hdr_size, need_space;
 
        if (mbox_sync_seek(sync_ctx, mails[idx].from_offset) < 0)
                return -1;
@@ -271,6 +284,7 @@ static int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx,
        mail_ctx.seq = seq;
        mail_ctx.header = sync_ctx->header;
 
+       hdr_offset = mails[idx].offset;
        mail_ctx.mail.offset = mails[idx].offset;
        mail_ctx.mail.body_size = mails[idx].body_size;
 
@@ -293,96 +307,48 @@ static int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx,
        sync_ctx->prev_msg_uid = old_prev_msg_uid;
        sync_ctx->dest_first_mail = FALSE;
 
-       mail_ctx.mail.space =
-               -(ssize_t)(str_len(mail_ctx.header) -
-                          (mail_ctx.body_offset - mail_ctx.hdr_offset));
-       i_assert(mail_ctx.mail.space == mails[idx].space);
+       old_hdr_size = mail_ctx.body_offset - mail_ctx.hdr_offset;
+       need_space = str_len(mail_ctx.header) - mail_ctx.mail.space -
+               old_hdr_size;
+       i_assert(need_space == -mails[idx].space);
+       i_assert(space_diff >= need_space);
 
-       if (mail_ctx.mail.space <= 0)
-               mbox_sync_headers_add_space(&mail_ctx, extra_per_mail);
-       else if (mail_ctx.mail.space <= extra_per_mail) {
-               mbox_sync_headers_add_space(&mail_ctx, extra_per_mail -
-                                           mail_ctx.mail.space);
-       } else {
+       if (space_diff - need_space < (uoff_t)mail_ctx.mail.space) {
                mbox_sync_headers_remove_space(&mail_ctx, mail_ctx.mail.space -
-                                              extra_per_mail);
+                                              (space_diff - need_space));
+       } else {
+               mbox_sync_headers_add_space(&mail_ctx, space_diff - need_space -
+                                           mail_ctx.mail.space);
        }
+       mails[idx].offset = mail_ctx.mail.offset;
+       mails[idx].space = mail_ctx.mail.space;
 
-       /* now we have to move it. first move the body of the message,
-          then write the header and leave the extra space to beginning of
-          headers. */
+       /* move the body of this message and headers of next message forward,
+          then write the headers */
        offset = sync_ctx->input->v_offset;
-       if (mbox_move(sync_ctx, offset + mails[idx+1].space, offset,
-                     *end_offset - offset - mails[idx+1].space) < 0)
+       dest_offset = offset + space_diff;
+       if (mbox_move(sync_ctx, dest_offset, offset,
+                     end_offset - dest_offset) < 0)
                return -1;
-       mails[idx+1].from_offset += mails[idx+1].space;
-
-       *end_offset = offset + mails[idx+1].space - str_len(mail_ctx.header);
-
-       if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header),
-                       str_len(mail_ctx.header), *end_offset) < 0) {
-               mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
-               return -1;
-       }
-
-       mails[idx].offset = *end_offset;
-       mails[idx].space += mails[idx+1].space - extra_per_mail;
-       return 0;
-}
-
-static int mbox_sync_fill_leftover(struct mbox_sync_context *sync_ctx,
-                                  struct mbox_sync_mail *mails,
-                                  uint32_t seq, uint32_t idx,
-                                  uoff_t start_offset, uoff_t end_offset)
-{
-       struct mbox_sync_mail_context mail_ctx;
-       uint32_t old_prev_msg_uid;
-
-       i_assert(start_offset < end_offset);
-
-       i_stream_seek(sync_ctx->input, mails[idx].offset);
-
-       memset(&mail_ctx, 0, sizeof(mail_ctx));
-       mail_ctx.sync_ctx = sync_ctx;
-       mail_ctx.seq = seq;
-       mail_ctx.header = sync_ctx->header;
-
-       mail_ctx.mail.offset = mails[idx].offset;
-       mail_ctx.mail.body_size = mails[idx].body_size;
-
-       /* mbox_sync_parse_next_mail() checks that UIDs are growing,
-          so we have to fool it. */
-        old_prev_msg_uid = sync_ctx->prev_msg_uid;
-        sync_ctx->prev_msg_uid = mails[idx].uid-1;
-       sync_ctx->dest_first_mail = seq == 1;
-
-       mbox_sync_parse_next_mail(sync_ctx->input, &mail_ctx, TRUE);
-       mbox_sync_update_header_from(&mail_ctx, &mails[idx]);
-
-        sync_ctx->prev_msg_uid = old_prev_msg_uid;
-       sync_ctx->dest_first_mail = FALSE;
-
-       mbox_sync_headers_add_space(&mail_ctx,end_offset - start_offset);
 
        if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header),
-                       str_len(mail_ctx.header), start_offset) < 0) {
+                       str_len(mail_ctx.header), hdr_offset) < 0) {
                mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
                return -1;
        }
 
-       /* just a cleanup - shouldn't be needed anymore */
-       mails[idx].offset = start_offset;
-       mails[idx].space = 0;
        return 0;
 }
 
-int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx,
-                     uint32_t first_seq, uint32_t last_seq, off_t extra_space)
+/* extra_space specifies how many bytes from last_seq's space will be left
+   over after all the rewrites. */
+int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx, uoff_t extra_space,
+                     uint32_t first_seq, uint32_t last_seq)
 {
        struct mbox_sync_mail *mails;
-       size_t size;
-       uoff_t offset, start_offset, end_offset, dest_offset;
+       uoff_t offset, end_offset, dest_offset, space_diff;
        uint32_t idx, extra_per_mail;
+       size_t size;
        int ret = 0;
 
        i_assert(first_seq != last_seq);
@@ -396,83 +362,71 @@ int mbox_sync_rewrite(struct mbox_sync_context *sync_ctx,
           data which hasn't yet been copied backwards. to avoid too much
           complexity, we just leave all the rest of the extra space to first
           mail */
-       extra_per_mail = extra_space / (last_seq - first_seq + 1);
        idx = last_seq - first_seq;
-
-       if (mails[idx].uid != 0)
-               mails[idx].space -= extra_per_mail;
-       i_assert(mails[idx].space >= 0);
-       end_offset = mails[idx].offset + mails[idx].space;
+       extra_per_mail = extra_space / (idx + 1);
 
        /* after expunge the next mail must have been missing space, or we
           would have moved it backwards already */
        i_assert(mails[0].space < 0 || mails[0].uid == 0);
-       start_offset = mails[0].offset;
 
-       /* start moving backwards */
+       /* start moving backwards. */
        do {
+               /* this message's body is always moved space_diff bytes
+                  forward along with next message's headers, so current
+                  message gets temporarily space_diff amount of extra
+                  whitespace.
+
+                  the moving stops at next message's beginning of extra
+                  space. each message gets left extra_per_mail bytes of
+                  space. what gets left over is given to first message */
+               i_assert(mails[idx].space > 0);
+               space_diff = mails[idx].space;
+               end_offset = mails[idx].offset + mails[idx].space;
+
+               if (mails[idx].uid != 0) {
+                       space_diff -= extra_per_mail;
+                       end_offset -= extra_per_mail;
+                       mails[idx].space = extra_per_mail;
+               }
+
                idx--;
                if (mails[idx].space <= 0 && mails[idx].uid != 0) {
                        /* offset points to beginning of headers. read the
                           header again, update it and give enough space to
-                          it */
+                          fill space_diff */
                        if (mbox_sync_read_and_move(sync_ctx, mails,
                                                    first_seq + idx, idx,
-                                                   extra_per_mail,
-                                                   &end_offset) < 0) {
+                                                   space_diff,
+                                                   end_offset) < 0) {
                                ret = -1;
                                break;
                        }
                } else {
-                       /* X-Keywords: xx [offset]     \n
+                       /* X-Keywords: xx    [offset]\n
                           ...
-                          X-Keywords: xx    [end_offset] \n
+                          X-Keywords: xx    [end_offset]   \n
 
                           move data forward so mails before us gets the extra
                           space (ie. we temporarily get more space to us) */
                        offset = mails[idx].offset + mails[idx].space;
-                       dest_offset = offset + mails[idx+1].space;
+                       dest_offset = offset + space_diff;
                        if (mbox_move(sync_ctx, dest_offset, offset,
                                      end_offset - dest_offset) < 0) {
                                ret = -1;
                                break;
                        }
 
-                       mails[idx+1].from_offset += mails[idx+1].space;
-
-                       mails[idx].space += mails[idx+1].space;
-                       if (mails[idx].uid != 0)
-                               mails[idx].space -= extra_per_mail;
-                       i_assert(mails[idx].space > 0);
-                       end_offset = mails[idx].offset + mails[idx].space;
-               }
-       } while (idx > 0);
-
-       if (end_offset != start_offset) {
-               /* some space was left over - give it to first message. */
-               if (mails[0].uid == 0) {
-                       /* "body" start_offset .. end_offset "\nFrom .."
-                          we need to move From-line to start_offset */
-                       offset = mails[1].offset;
-                       if (mbox_move(sync_ctx, start_offset, end_offset,
-                                     offset - end_offset) < 0)
+                       if (mbox_fill_space(sync_ctx, offset,
+                                           dest_offset - offset) < 0) {
                                ret = -1;
-                       mails[1].from_offset -= end_offset - start_offset;
-                       idx++;
+                               break;
+                       }
 
-                       start_offset += offset - end_offset;
-                       end_offset = offset;
-               } else {
-                       /* "\nFrom ..\n" start_offset .. end_offset "hdr.." */
-               }
+                       mails[idx].space += space_diff;
+               }
 
-               /* now parse it again and give it more space */
-               mails[idx+1].space = 0; /* from_offset doesn't move.. */
-               if (mbox_sync_fill_leftover(sync_ctx, mails,
-                                           first_seq + idx, idx,
-                                           start_offset, end_offset) < 0)
-                       ret = -1;
-       }
+               mails[idx+1].from_offset += space_diff;
+       } while (idx > 0);
 
        istream_raw_mbox_flush(sync_ctx->input);
        return ret;
index 909dc483e3bdd5abc4b83029b2ed9ddab2166142..139c87db57346f7a3b8fe0b518c340f2ec99e4aa 100644 (file)
@@ -31,7 +31,8 @@ static void mbox_sync_move_buffer(struct mbox_sync_mail_context *ctx,
        } else {
                /* FIXME: if (diff < ctx->space && pos < ctx->offset) then
                   move the data only up to space offset and give/take the
-                  space from there. update header_last_change accordingly. */
+                  space from there. update header_last_change accordingly.
+                  (except pos and offset can't be compared directly) */
                ctx->header_last_change = (size_t)-1;
                for (i = 0; i < MBOX_HDR_COUNT; i++) {
                        if (ctx->hdr_pos[i] > pos &&
index 47f939f9256230f0329d365c3ceff246b35e9365..cc92ebde0b058f1a5c5dc56f5a8166d832cd8b40 100644 (file)
@@ -605,8 +605,8 @@ mbox_sync_handle_missing_space(struct mbox_sync_mail_context *mail_ctx)
                sync_ctx->expunged_space = 0;
        }
 
-       if (mbox_sync_rewrite(sync_ctx, sync_ctx->need_space_seq, sync_ctx->seq,
-                             sync_ctx->space_diff) < 0)
+       if (mbox_sync_rewrite(sync_ctx, sync_ctx->space_diff,
+                             sync_ctx->need_space_seq, sync_ctx->seq) < 0)
                return -1;
 
        update_from_offsets(sync_ctx->ibox, sync_ctx->t, sync_ctx->mails,
@@ -816,9 +816,9 @@ static int mbox_sync_handle_eof_updates(struct mbox_sync_context *sync_ctx,
                        buffer_append(sync_ctx->mails, &mail_ctx->mail,
                                      sizeof(mail_ctx->mail));
 
-                       if (mbox_sync_rewrite(sync_ctx,
+                       if (mbox_sync_rewrite(sync_ctx, extra_space,
                                              sync_ctx->need_space_seq,
-                                             sync_ctx->seq, extra_space) < 0)
+                                             sync_ctx->seq) < 0)
                                return -1;
 
                        update_from_offsets(sync_ctx->ibox, sync_ctx->t,