mbox-sync-rewrite.c revision dc8552739fa29f011ab71ec383ec6d580a5a9661
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "lib.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "buffer.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "istream.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "ostream.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "str.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "write-full.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "message-parser.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "mbox-storage.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "mbox-sync-private.h"
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White#include "istream-raw-mbox.h"
6863a963d4dd3d2e855f74ae8a7ff640bd4e1181Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whiteint mbox_move(struct mbox_sync_context *sync_ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t dest, uoff_t source, uoff_t size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White struct istream *input;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White struct ostream *output;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White off_t ret;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(size < OFF_T_MAX);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (size == 0 || source == dest)
6863a963d4dd3d2e855f74ae8a7ff640bd4e1181Liam P. White return 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White istream_raw_mbox_flush(sync_ctx->input);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White output = o_stream_create_file(sync_ctx->fd, default_pool, 4096, FALSE);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_stream_seek(sync_ctx->file_input, source);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White o_stream_seek(output, dest);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White input = i_stream_create_limit(default_pool, sync_ctx->file_input,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White source, size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ret = o_stream_send_istream(output, input);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_stream_unref(input);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ret == (off_t)size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ret = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White else if (ret >= 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_storage_set_critical(sync_ctx->ibox->box.storage,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White "mbox_move(%"PRIuUOFF_T", %"PRIuUOFF_T", %"PRIuUOFF_T
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ") moved only %"PRIuUOFF_T" bytes in mbox file %s",
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White dest, source, size, (uoff_t)ret, sync_ctx->ibox->path);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ret = -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else if (ret < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White errno = output->stream_errno;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_set_syscall_error(sync_ctx->ibox,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White "o_stream_send_istream()");
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
84d3dac7b0c792923b87e7d0df5b100ad98a4665Liam P. White o_stream_unref(output);
4c32cf8317b67dfb340e6d8744fc87b3fa121e2aTomasz Boczkowski return (int)ret;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whitestatic int mbox_fill_space(struct mbox_sync_context *sync_ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t offset, uoff_t size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White unsigned char space[1024];
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White memset(space, ' ', sizeof(space));
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White while (size > sizeof(space)) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (pwrite_full(sync_ctx->fd, space,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sizeof(space), offset) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size -= sizeof(space);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (pwrite_full(sync_ctx->fd, space, size, offset) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whitestatic void
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whitembox_sync_headers_add_space(struct mbox_sync_mail_context *ctx, size_t size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t data_size, pos, start_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White const unsigned char *data;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White void *p;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(size < SSIZE_T_MAX);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->pseudo)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White start_pos = ctx->hdr_pos[MBOX_HDR_X_IMAPBASE];
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White else {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* Append at the end of X-Keywords header,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White or X-UID if it doesn't exist */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White start_pos = ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] != (size_t)-1 ?
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] :
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->hdr_pos[MBOX_HDR_X_UID];
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(start_pos != (size_t)-1);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data = str_data(ctx->header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data_size = str_len(ctx->header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White for (pos = start_pos; pos < data_size; pos++) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (data[pos] == '\n') {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* possibly continues in next line */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (pos+1 == data_size || !IS_LWSP(data[pos+1]))
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White break;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White start_pos = pos+1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else if (!IS_LWSP(data[pos])) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White start_pos = pos+1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* pos points to end of header now, and start_pos to beginning
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White of whitespace. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White buffer_copy(ctx->header, pos + size,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header, pos, (size_t)-1);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White p = buffer_get_space_unsafe(ctx->header, pos, size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White memset(p, ' ', size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->header_first_change > pos)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_first_change = pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_last_change = (size_t)-1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.offset = ctx->hdr_offset + start_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.space = (pos - start_pos) + size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whitestatic void mbox_sync_header_remove_space(struct mbox_sync_mail_context *ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t start_pos, size_t *size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White const unsigned char *data;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t data_size, pos, last_line_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* find the end of the LWSP */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data = str_data(ctx->header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data_size = str_len(ctx->header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White for (pos = last_line_pos = start_pos; pos < data_size; pos++) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (data[pos] == '\n') {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* possibly continues in next line */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (pos+1 == data_size || !IS_LWSP(data[pos+1])) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data_size = pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White break;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White last_line_pos = pos+1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else if (!IS_LWSP(data[pos])) {
12d084654ee6f91cc12b6218508ee5d3e37de2baLiam P. White start_pos = last_line_pos = pos+1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
12d084654ee6f91cc12b6218508ee5d3e37de2baLiam P. White }
12d084654ee6f91cc12b6218508ee5d3e37de2baLiam P. White
12d084654ee6f91cc12b6218508ee5d3e37de2baLiam P. White if (start_pos == data_size)
12d084654ee6f91cc12b6218508ee5d3e37de2baLiam P. White return;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* and remove what we can */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->header_first_change > start_pos)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_first_change = start_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_last_change = (size_t)-1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (data_size - start_pos <= *size) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* remove it all */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_move_buffer(ctx, start_pos, 0, data_size - start_pos);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White *size -= data_size - start_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* we have more space than needed. since we're removing from
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White the beginning of header instead of end, we don't have to
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White worry about multiline-headers. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_move_buffer(ctx, start_pos, 0, *size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (last_line_pos <= start_pos + *size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White last_line_pos = start_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White else
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White last_line_pos -= *size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data_size -= *size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White *size = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->mail.space < (off_t)(data_size - last_line_pos)) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.space = data_size - last_line_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.offset = ctx->hdr_offset + last_line_pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whitestatic void mbox_sync_headers_remove_space(struct mbox_sync_mail_context *ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t size)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White static enum header_position space_positions[] = {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White MBOX_HDR_X_UID,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White MBOX_HDR_X_KEYWORDS,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White MBOX_HDR_X_IMAPBASE
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White };
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White enum header_position pos;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White int i;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.space = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.offset = ctx->hdr_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White for (i = 0; i < 3 && size > 0; i++) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White pos = space_positions[i];
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->hdr_pos[pos] != (size_t)-1) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_header_remove_space(ctx, ctx->hdr_pos[pos],
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White &size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* FIXME: see if we could remove X-Keywords header completely */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whiteint mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t old_hdr_size, new_hdr_size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(ctx->sync_ctx->ibox->mbox_lock_type == F_WRLCK);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White old_hdr_size = ctx->body_offset - ctx->hdr_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White new_hdr_size = str_len(ctx->header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (new_hdr_size <= old_hdr_size) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* add space. note that we must call add_space() even if we're
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White not adding anything so mail.offset gets fixed. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_headers_add_space(ctx, old_hdr_size - new_hdr_size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else if (new_hdr_size > old_hdr_size) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* try removing the space where we can */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_headers_remove_space(ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White new_hdr_size - old_hdr_size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White new_hdr_size = str_len(ctx->header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (new_hdr_size <= old_hdr_size) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* good, we removed enough. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(new_hdr_size == old_hdr_size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else if (move_diff < 0 &&
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White new_hdr_size - old_hdr_size <= (uoff_t)-move_diff) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* moving backwards - we can use the extra space from
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White it, just update expunged_space accordingly */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(ctx->mail.space == 0);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(ctx->sync_ctx->expunged_space >=
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White (off_t)(new_hdr_size - old_hdr_size));
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->sync_ctx->expunged_space -=
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White new_hdr_size - old_hdr_size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* couldn't get enough space */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(ctx->mail.space == 0);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->mail.space =
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White -(ssize_t)(new_hdr_size - old_hdr_size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(ctx->mail.space >= 0);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->header_first_change == (size_t)-1 && move_diff == 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* no changes actually. we get here if index sync record told
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White us to do something that was already there */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return 1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (move_diff != 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* forget about partial write optimizations */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_first_change = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_last_change = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->header_last_change != (size_t)-1 &&
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->header_last_change != 0)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White str_truncate(ctx->header, ctx->header_last_change);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (pwrite_full(ctx->sync_ctx->fd,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White str_data(ctx->header) + ctx->header_first_change,
2b9e5de12a7774e2f1db30c1c7a762eb76093e1aLiam P. White str_len(ctx->header) - ctx->header_first_change,
2b9e5de12a7774e2f1db30c1c7a762eb76093e1aLiam P. White ctx->hdr_offset + ctx->header_first_change +
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White move_diff) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_set_syscall_error(ctx->sync_ctx->ibox, "pwrite_full()");
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (ctx->sync_ctx->dest_first_mail) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->sync_ctx->base_uid_last =
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->sync_ctx->update_base_uid_last;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ctx->sync_ctx->update_base_uid_last = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White istream_raw_mbox_flush(ctx->sync_ctx->input);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return 1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whitestatic int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White struct mbox_sync_mail *mails,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uint32_t seq, uint32_t idx, uint32_t padding,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White off_t move_diff, uoff_t expunged_space,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t end_offset, int first_nonexpunged)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White struct mbox_sync_mail_context mail_ctx;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uint32_t old_prev_msg_uid;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t hdr_offset, offset, dest_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t need_space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mbox_sync_seek(sync_ctx, mails[idx].from_offset) < 0)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White memset(&mail_ctx, 0, sizeof(mail_ctx));
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_ctx.sync_ctx = sync_ctx;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_ctx.seq = seq;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_ctx.header = sync_ctx->header;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_ctx.uidl = sync_ctx->uidl;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White str_truncate(mail_ctx.uidl, 0);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White hdr_offset = istream_raw_mbox_get_header_offset(sync_ctx->input);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_ctx.mail.offset = hdr_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail_ctx.mail.body_size = mails[idx].body_size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* mbox_sync_parse_next_mail() checks that UIDs are growing,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White so we have to fool it. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White old_prev_msg_uid = sync_ctx->prev_msg_uid;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->prev_msg_uid = mails[idx].uid == 0 ? 0 : mails[idx].uid-1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mails[idx].from_offset+1 - expunged_space != 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->dest_first_mail = mails[idx].from_offset == 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* we need to skip over the initial \n (it's already counted in
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White expunged_space) */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->dest_first_mail = TRUE;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].from_offset++;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_parse_next_mail(sync_ctx->input, &mail_ctx);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mails[idx].space != 0)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_update_header_from(&mail_ctx, &mails[idx]);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White else {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* updating might just try to add headers and mess up our
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White calculations completely. so only add the EOH here. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mail_ctx.have_eoh)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White str_append_c(mail_ctx.header, '\n');
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (first_nonexpunged && expunged_space > 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* move From-line (after parsing headers so we don't
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White overwrite them) */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mbox_move(sync_ctx, mails[idx].from_offset - expunged_space,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].from_offset,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].offset - mails[idx].from_offset) < 0)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->prev_msg_uid = old_prev_msg_uid;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->dest_first_mail = FALSE;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White need_space = str_len(mail_ctx.header) - mail_ctx.mail.space -
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White (mail_ctx.body_offset - mail_ctx.hdr_offset);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(need_space == (uoff_t)-mails[idx].space);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mails[idx].space == 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* don't touch spacing */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else if (padding < (uoff_t)mail_ctx.mail.space) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_headers_remove_space(&mail_ctx, mail_ctx.mail.space -
1f6daa293cacc62d85a023412c70534a12f6e99aMarc Jeanmougin padding);
c652591f8105502bfed1dcd3d7207681932a7515Kris De Gussem } else {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_sync_headers_add_space(&mail_ctx, padding -
aa9235c966804d9b8f8daa083a2d123d9d47d2bbMarc Jeanmougin mail_ctx.mail.space);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* move the body of this message and headers of next message forward,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White then write the headers */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White offset = sync_ctx->input->v_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White dest_offset = offset + move_diff;
93cce75c515069567a34a17f5f75a9742881695dJon A. Cruz i_assert(offset <= end_offset);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mbox_move(sync_ctx, dest_offset, offset, end_offset - offset) < 0)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* the header may actually be moved backwards if there was expunged
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White space which we wanted to remove */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(dest_offset >= str_len(mail_ctx.header));
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White dest_offset -= str_len(mail_ctx.header);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (pwrite_full(sync_ctx->fd, str_data(mail_ctx.header),
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White str_len(mail_ctx.header), dest_offset) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mbox_set_syscall_error(sync_ctx->ibox, "pwrite_full()");
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
777bbe32326f8cdbebf76ab0b898e65105e8ccf3Jon A. Cruz
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].offset = dest_offset +
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White (mail_ctx.mail.offset - mail_ctx.hdr_offset);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].space = mail_ctx.mail.space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mails[idx].from_offset == 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->base_uid_last =
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->update_base_uid_last;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White sync_ctx->update_base_uid_last = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. Whiteint mbox_sync_rewrite(struct mbox_sync_context *sync_ctx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t end_offset, off_t move_diff, uoff_t extra_space,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uint32_t first_seq, uint32_t last_seq)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White{
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White struct mbox_sync_mail *mails;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t offset, dest_offset, next_end_offset, next_move_diff;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uoff_t start_offset, expunged_space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White uint32_t idx, first_nonexpunged_idx, padding_per_mail;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White size_t size;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White int ret = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(sync_ctx->ibox->mbox_lock_type == F_WRLCK);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails = buffer_get_modifyable_data(sync_ctx->mails, &size);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(size / sizeof(*mails) == last_seq - first_seq + 1);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* if there's expunges in mails[], we would get more correct balancing
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White by counting only them here. however, that might make us overwrite
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White data which hasn't yet been copied backwards. to avoid too much
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White complexity, we just leave all the rest of the extra space to first
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White idx = last_seq - first_seq + 1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White padding_per_mail = extra_space / idx;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* after expunge the next mail must have been missing space, or we
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White would have moved it backwards already */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White expunged_space = 0;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White start_offset = mails[0].from_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White for (first_nonexpunged_idx = 0;; first_nonexpunged_idx++) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(first_nonexpunged_idx != idx);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if ((mails[first_nonexpunged_idx].flags & MBOX_EXPUNGED) == 0)
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White break;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White expunged_space += mails[first_nonexpunged_idx].space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(mails[first_nonexpunged_idx].space < 0);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* start moving backwards. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White while (idx > first_nonexpunged_idx) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White idx--;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (idx == first_nonexpunged_idx) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* give the rest of the extra space to first mail.
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White we might also have to move the mail backwards to
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White fill the expunged space */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White padding_per_mail = move_diff + expunged_space +
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White next_end_offset = mails[idx].offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mails[idx].space <= 0 &&
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White (mails[idx].flags & MBOX_EXPUNGED) == 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* give space to this mail. end_offset is left to
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White contain this message's From-line (ie. below we
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White move only headers + body). */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White int first_nonexpunged = idx == first_nonexpunged_idx;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White next_move_diff = -mails[idx].space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mbox_sync_read_and_move(sync_ctx, mails,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White first_seq + idx, idx,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White padding_per_mail,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White move_diff, expunged_space,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White end_offset,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White first_nonexpunged) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ret = -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White break;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White move_diff -= next_move_diff + mails[idx].space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White } else {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White /* this mail provides more space. just move it forward
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White from the extra space offset and set end_offset to
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White point to beginning of extra space. that way the
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White header will be moved along with previous mail's
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White body.
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if this is expunged mail, we're moving following
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mail's From-line and maybe headers. */
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White offset = mails[idx].offset + mails[idx].space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White dest_offset = offset + move_diff;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(offset <= end_offset);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mbox_move(sync_ctx, dest_offset, offset,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White end_offset - offset) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ret = -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White break;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White move_diff += mails[idx].space;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if ((mails[idx].flags & MBOX_EXPUNGED) == 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White move_diff -= padding_per_mail;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].space = padding_per_mail;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White if (mbox_fill_space(sync_ctx, move_diff +
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].offset,
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White padding_per_mail) < 0) {
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White ret = -1;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White break;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].offset += move_diff;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(move_diff >= 0 || idx == first_nonexpunged_idx);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White end_offset = next_end_offset;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White mails[idx].from_offset += move_diff;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White }
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(mails[idx].from_offset == start_offset);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White i_assert(move_diff + (off_t)expunged_space >= 0);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White istream_raw_mbox_flush(sync_ctx->input);
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White return ret;
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White}
a73b1f7fc9a9ba7e0d68f33292a885da6c2981d0Liam P. White