Mercurial > dovecot > core-2.2
changeset 198:e6e5fd3d4718 HEAD
EXPUNGE works with mbox. finally.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 09 Sep 2002 10:18:50 +0300 |
parents | 38d77994baa5 |
children | cf1279829ad1 |
files | src/lib-storage/index/mbox/mbox-expunge.c |
diffstat | 1 files changed, 127 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/mbox/mbox-expunge.c Mon Sep 09 10:18:37 2002 +0300 +++ b/src/lib-storage/index/mbox/mbox-expunge.c Mon Sep 09 10:18:50 2002 +0300 @@ -1,22 +1,47 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" +#include "iobuffer.h" +#include "mbox-index.h" #include "mbox-storage.h" +#include "mbox-lock.h" -int mbox_expunge_locked(IndexMailbox *ibox, +#include <fcntl.h> +#include <unistd.h> + +static int expunge_real(IndexMailbox *ibox, MailIndexRecord *rec, + unsigned int seq, IOBuffer *inbuf, IOBuffer *outbuf, MailExpungeFunc expunge_func, void *context) { - MailIndexRecord *rec; - unsigned int seq, uid; + uoff_t offset, end_offset, from_offset, copy_size; + unsigned int uid; + unsigned char *data; + size_t size; + int expunges; - /* FIXME: open the mbox file, lock it, and remove the deleted - blocks. probably better to do it in small blocks than to - memmove() megabytes of data.. */ + if (seq == 1) + end_offset = 0; + else { + /* we need to find offset to beginning of From-line. + not the fastest way maybe, but easiest.. */ + rec = ibox->index->lookup(ibox->index, seq-1); + + if (!mbox_mail_get_start_offset(ibox->index, rec, &offset)) + return FALSE; + end_offset = offset + rec->header_size + rec->body_size; - if (!index_expunge_seek_first(ibox, &seq, &rec)) - return FALSE; + /* get back to the deleted record */ + rec = ibox->index->next(ibox->index, rec); + } + expunges = FALSE; while (rec != NULL) { + if (!mbox_mail_get_start_offset(ibox->index, rec, &offset)) + return FALSE; + + from_offset = end_offset; + end_offset = offset + rec->header_size + rec->body_size; + if (rec->msg_flags & MAIL_DELETED) { /* save UID before deletion */ uid = rec->uid; @@ -28,10 +53,103 @@ if (expunge_func != NULL) expunge_func(&ibox->box, seq, uid, context); seq--; + + if (!expunges) { + /* first expunged record, seek to position + where we want to begin writing */ + if (!io_buffer_seek(outbuf, from_offset)) + return FALSE; + expunges = TRUE; + } + } else if (expunges) { + /* seek to wanted input position, and copy + this messages */ + i_assert(inbuf->offset <= from_offset); + io_buffer_skip(inbuf, from_offset - inbuf->offset); + + if (outbuf->offset == 0) { + /* we're writing to beginning of mbox, so we + don't want the [\r]\n there */ + while (io_buffer_read_data(inbuf, &data, + &size, 1) == 0) ; + if (size > 0 && data[0] == '\n') + io_buffer_skip(inbuf, 1); + else if (size > 1 && data[0] == '\r' && + data[1] == '\n') + io_buffer_skip(inbuf, 2); + } + + copy_size = end_offset - inbuf->offset; + if (io_buffer_send_iobuffer(outbuf, inbuf, + copy_size) < 0) + return FALSE; } + rec = ibox->index->next(ibox->index, rec); seq++; } - return TRUE; + /* copy the rest as well, should be only \n but someone might + as well just appended more data.. */ + copy_size = inbuf->size - inbuf->offset; + return io_buffer_send_iobuffer(outbuf, inbuf, copy_size) > 0; } + +int mbox_expunge_locked(IndexMailbox *ibox, + MailExpungeFunc expunge_func, void *context) +{ + MailIndexRecord *rec; + IOBuffer *inbuf, *outbuf; + unsigned int seq; + int fd, failed; + + if (!index_expunge_seek_first(ibox, &seq, &rec)) + return FALSE; + + if (rec == NULL) { + /* no deleted messages */ + return TRUE; + } + + fd = open(ibox->index->mbox_path, O_RDWR); + if (fd == -1) { + mail_storage_set_error(ibox->box.storage, + "Error opening mbox file %s: %m", + ibox->index->mbox_path); + return FALSE; + } + + if (!mbox_lock(ibox->index, ibox->index->mbox_path, fd)) { + (void)close(fd); + return FALSE; + } + + inbuf = io_buffer_create_mmap(fd, default_pool, + MAIL_MMAP_BLOCK_SIZE, 0); + outbuf = io_buffer_create_file(fd, default_pool, 4096); + + failed = !expunge_real(ibox, rec, seq, inbuf, outbuf, + expunge_func, context); + + if (failed && outbuf->offset > 0) { + /* we moved some of the data. move the rest as well so there + won't be invalid holes in mbox file */ + i_assert(inbuf->offset <= inbuf->size); + (void)io_buffer_send_iobuffer(outbuf, inbuf, + inbuf->size - inbuf->offset); + } + + if (ftruncate(outbuf->fd, outbuf->offset) < 0) { + mail_storage_set_error(ibox->box.storage, "ftruncate() failed " + "for mbox file %s: %m", + ibox->index->mbox_path); + failed = TRUE; + } + + (void)mbox_unlock(ibox->index, ibox->index->mbox_path, fd); + (void)close(fd); + io_buffer_destroy(inbuf); + io_buffer_destroy(outbuf); + + return !failed; +}