Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/mbox/mbox-expunge.c @ 416:cca1c7004a6f HEAD
Bugfixes to mbox and OBuffer handling.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 14 Oct 2002 18:13:07 +0300 |
parents | 1f0e7229ee58 |
children | 925d6eb5f8be |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "ibuffer.h" #include "obuffer.h" #include "mbox-index.h" #include "mbox-storage.h" #include "mbox-lock.h" #include <fcntl.h> #include <unistd.h> static int expunge_real(IndexMailbox *ibox, MailIndexRecord *rec, unsigned int seq, IBuffer *inbuf, OBuffer *outbuf, MailExpungeFunc expunge_func, void *context) { uoff_t offset, end_offset, from_offset, copy_size, old_limit; unsigned int uid; const unsigned char *data; size_t size; int expunges, failed; 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; /* get back to the deleted record */ rec = ibox->index->next(ibox->index, rec); } old_limit = inbuf->v_limit; 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; if (!ibox->index->expunge(ibox->index, rec, seq, FALSE)) return FALSE; 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 (!o_buffer_seek(outbuf, from_offset)) return FALSE; expunges = TRUE; } } else if (expunges) { /* seek to wanted input position, and copy this messages */ i_assert(inbuf->v_offset <= from_offset); i_buffer_skip(inbuf, from_offset - inbuf->v_offset); if (outbuf->offset == 0) { /* we're writing to beginning of mbox, so we don't want the [\r]\n there */ (void)i_buffer_read_data(inbuf, &data, &size, 1); if (size > 0 && data[0] == '\n') i_buffer_skip(inbuf, 1); else if (size > 1 && data[0] == '\r' && data[1] == '\n') i_buffer_skip(inbuf, 2); } i_buffer_set_read_limit(inbuf, end_offset); failed = o_buffer_send_ibuffer(outbuf, inbuf) < 0; i_buffer_set_read_limit(inbuf, old_limit); if (failed || inbuf->v_offset != end_offset) return FALSE; } rec = ibox->index->next(ibox->index, rec); seq++; } i_buffer_skip(inbuf, end_offset - inbuf->v_offset); /* copy the rest as well, should be only \n but someone might as well just appended more data.. but if we've deleted all mail, don't write the only \n there. */ copy_size = inbuf->v_size - inbuf->v_offset; if (outbuf->offset == 0 && copy_size == 1) return TRUE; return o_buffer_send_ibuffer(outbuf, inbuf) >= 0; } int mbox_expunge_locked(IndexMailbox *ibox, MailExpungeFunc expunge_func, void *context) { MailIndexRecord *rec; IBuffer *inbuf; OBuffer *outbuf; unsigned int seq; int failed; if (!index_expunge_seek_first(ibox, &seq, &rec)) return FALSE; if (rec == NULL) { /* no deleted messages */ return TRUE; } inbuf = mbox_file_open(ibox->index, 0, TRUE); if (inbuf == NULL) return FALSE; if (!mbox_lock_write(ibox->index)) { i_buffer_unref(inbuf); return FALSE; } t_push(); outbuf = o_buffer_create_file(ibox->index->mbox_fd, data_stack_pool, 4096, IO_PRIORITY_DEFAULT, FALSE); 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 */ (void)o_buffer_send_ibuffer(outbuf, inbuf); } if (ftruncate(ibox->index->mbox_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); o_buffer_unref(outbuf); t_pop(); return !failed; }