mail-transaction-log.c revision 5d04f56a6d953287f82dc20ac2f307d30deebf76
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (C) 2003-2004 Timo Sirainen */
10962368c30afde135743fd9796122e88a708e87Stephan Bosch/* this lock should never exist for a long time.. */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 120
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Boschmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch const char *path);
10962368c30afde135743fd9796122e88a708e87Stephan Boschstatic int mail_transaction_log_rotate(struct mail_transaction_log *log);
10962368c30afde135743fd9796122e88a708e87Stephan Boschmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
10962368c30afde135743fd9796122e88a708e87Stephan Boschstatic int mail_transaction_log_lock_head(struct mail_transaction_log *log);
10962368c30afde135743fd9796122e88a708e87Stephan Boschmail_transaction_log_file_set_corrupted(struct mail_transaction_log_file *file,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch const char *fmt, ...)
10962368c30afde135743fd9796122e88a708e87Stephan Bosch mail_index_file_set_syscall_error(file->log->index,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch "Corrupted transaction log file %s: %s",
10962368c30afde135743fd9796122e88a708e87Stephan Bosch !(((file)->hdr.file_seq == (index)->hdr->log_file_seq && \
10962368c30afde135743fd9796122e88a708e87Stephan Bosch sizeof(struct mail_transaction_log_header)) || \
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch ((file)->hdr.prev_file_seq == (index)->hdr->log_file_seq && \
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Bosch (file)->hdr.prev_file_offset == (index)->hdr->log_file_offset))
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschstatic int mail_transaction_log_check_file_seq(struct mail_transaction_log *log)
10962368c30afde135743fd9796122e88a708e87Stephan Bosch unsigned int lock_id;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch ret = mail_index_lock_shared(index, TRUE, &lock_id);
10962368c30afde135743fd9796122e88a708e87Stephan Bosch else if (INDEX_HAS_MISSING_LOGS(index, file)) {
10962368c30afde135743fd9796122e88a708e87Stephan Bosch /* broken - fix it by creating a new log file */
10962368c30afde135743fd9796122e88a708e87Stephan Bosch (void)mail_transaction_log_file_lock(file, F_UNLCK);
10962368c30afde135743fd9796122e88a708e87Stephan Boschmail_transaction_log_open_or_create(struct mail_index *index)
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch log->head = mail_transaction_log_file_open_or_create(log, path);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* head log file isn't same as head index file -
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch shouldn't happen except in race conditions. lock them and
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch check again - FIXME: missing error handling. */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch (void)mail_transaction_log_check_file_seq(log);
1faa520084b901b15d83d3d68baaee2535051defStephan Boschvoid mail_transaction_log_close(struct mail_transaction_log *log)
1faa520084b901b15d83d3d68baaee2535051defStephan Boschmail_transaction_log_file_dotlock(struct mail_transaction_log_file *file,
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch ret = file_unlock_dotlock(file->filepath, &file->log->dotlock);
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch mail_index_file_set_syscall_error(file->log->index,
ba592dc74a004ad47dfe58edcfc1ca7297551e39Phil Carmody "Dotlock was lost for transaction log file %s",
10962368c30afde135743fd9796122e88a708e87Stephan Bosch ret = file_lock_dotlock(file->filepath, NULL, FALSE,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch mail_index_file_set_syscall_error(file->log->index,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch "file_lock_dotlock()");
b9ee73a064b38d8aeec754b964cc34b23487387aTimo Sirainen "Timeout while waiting for release of "
10962368c30afde135743fd9796122e88a708e87Stephan Bosch "dotlock for transaction log file %s",
10962368c30afde135743fd9796122e88a708e87Stephan Boschmail_transaction_log_file_lock(struct mail_transaction_log_file *file,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch return mail_transaction_log_file_dotlock(file, lock_type);
b9ee73a064b38d8aeec754b964cc34b23487387aTimo Sirainen ret = file_wait_lock_full(file->fd, lock_type, DEFAULT_LOCK_TIMEOUT,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen mail_index_file_set_syscall_error(file->log->index,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch "file_wait_lock()");
b9ee73a064b38d8aeec754b964cc34b23487387aTimo Sirainen "Timeout while waiting for release of "
10962368c30afde135743fd9796122e88a708e87Stephan Bosch "%s fcntl() lock for transaction log file %s",
10962368c30afde135743fd9796122e88a708e87Stephan Bosch lock_type == F_WRLCK ? "exclusive" : "shared",
10962368c30afde135743fd9796122e88a708e87Stephan Boschmail_transaction_log_file_close(struct mail_transaction_log_file *file)
10962368c30afde135743fd9796122e88a708e87Stephan Bosch if (munmap(file->mmap_base, file->mmap_size) < 0) {
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(file->log->index,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch mail_index_file_set_syscall_error(file->log->index,
f74dbd3ff682fea040f60383e001620d1f1b09d3Stephan Boschmail_transaction_log_file_read_hdr(struct mail_transaction_log_file *file,
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch ret = pread_full(file->fd, &file->hdr, sizeof(file->hdr), 0);
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch if (mail_transaction_log_file_lock(file, F_RDLCK) < 0)
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* we have to fstat() again since it may have changed after
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(file->log->index,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch (void)mail_transaction_log_file_lock(file, F_UNLCK);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch (void)mail_transaction_log_file_lock(file, F_UNLCK);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch // FIXME: handle ESTALE
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(file->log->index,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch "pread_full()");
10962368c30afde135743fd9796122e88a708e87Stephan Bosch "unexpected end of file while reading header");
10962368c30afde135743fd9796122e88a708e87Stephan Bosch /* corrupted */
10962368c30afde135743fd9796122e88a708e87Stephan Bosch "Transaction log file %s: marked corrupted",
10962368c30afde135743fd9796122e88a708e87Stephan Bosch if (file->hdr.indexid != file->log->index->indexid &&
10962368c30afde135743fd9796122e88a708e87Stephan Bosch /* either index was just recreated, or transaction has wrong
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch indexid. we don't know here which one is the case, so we'll
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch just fail. If index->indexid == 0, we're rebuilding it and
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch we just want to lock the transaction log. */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch "Transaction log file %s: invalid indexid",
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch "used_size (%u) < old_size (%u)",
1faa520084b901b15d83d3d68baaee2535051defStephan Boschmail_transaction_log_file_create(struct mail_transaction_log *log,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* With dotlocking we might already have path.lock created, so this
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch filename has to be different. */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch fd = file_dotlock_open(path, NULL, LOG_NEW_DOTLOCK_SUFFIX,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(index, path,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch "file_dotlock_open()");
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* log creation is locked now - see if someone already created it */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(index, path,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch } else if (st.st_dev == dev && st.st_ino == ino) {
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* same file, still broken */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX,
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch mail_index_file_set_syscall_error(index, path, "open()");
10962368c30afde135743fd9796122e88a708e87Stephan Bosch hdr.prev_file_offset = index->hdr->log_file_offset;
10962368c30afde135743fd9796122e88a708e87Stephan Bosch if (log->head != NULL && hdr.file_seq <= log->head->hdr.file_seq) {
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* make sure the sequence grows */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(index, path,
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch "write_full()");
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch mail_index_file_set_syscall_error(index, path, "dup()");
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch if (file_dotlock_replace(path, LOG_NEW_DOTLOCK_SUFFIX, fd, FALSE) <= 0)
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* success */
10962368c30afde135743fd9796122e88a708e87Stephan Boschmail_transaction_log_file_fd_open(struct mail_transaction_log *log,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch mail_index_file_set_syscall_error(log->index, path, "stat()");
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch file = i_new(struct mail_transaction_log_file, 1);
10962368c30afde135743fd9796122e88a708e87Stephan Bosch ret = mail_transaction_log_file_read_hdr(file, &st);
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch /* corrupted header */
1faa520084b901b15d83d3d68baaee2535051defStephan Bosch fd = mail_transaction_log_file_create(log, path,
10962368c30afde135743fd9796122e88a708e87Stephan Bosch mail_index_file_set_syscall_error(log->index, path,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch ret = mail_transaction_log_file_read_hdr(file, &st);
10962368c30afde135743fd9796122e88a708e87Stephan Bosch for (p = &log->tail; *p != NULL; p = &(*p)->next) {
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch if ((*p)->hdr.file_seq >= file->hdr.file_seq) {
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch /* log replaced with file having same sequence as
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch previous one. shouldn't happen unless previous
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch log file was corrupted.. */
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Boschmail_transaction_log_file_open_or_create(struct mail_transaction_log *log,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch mail_index_file_set_syscall_error(log->index, path,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch fd = mail_transaction_log_file_create(log, path, 0, 0);
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch return mail_transaction_log_file_fd_open(log, path, fd);
10962368c30afde135743fd9796122e88a708e87Stephan Boschvoid mail_transaction_logs_clean(struct mail_transaction_log *log)
10962368c30afde135743fd9796122e88a708e87Stephan Bosch if ((*p)->refcount != 0)
unsigned int lock_id;
int ret;
return ret;
const char *path;
int ret;
void *data;
int ret;
ret = 0;
if (ret <= 0)
return ret;
size = 0;
if (size == 0)
ret = 0;
return ret;
if (!use_mmap) {
if (ret <= 0) {
if (ret < 0) {
return ret;
int ret = 0;
if (ret < 0)
return ret;
const void *data;
int ret;
return ret;
unsigned char *data;
expunges_before = 0;
exp++;
if (!two)
if (expunges_before != 0) {
if (uids) {
if (two) {
exp2++;
if (count != 0) {
if (uids) {
struct mail_index_transaction *t)
sizeof(struct mail_transaction_flag_update),
sizeof(struct mail_transaction_cache_update),
sizeof(struct mail_transaction_expunge),
struct mail_index_transaction *t)
const void *data;
if (deleted) {
dest++;
return ret;
const void *data;
if (size == 0)
size = 0;
if (external)
if (size != 0) {
int ret;
F_UNLCK);
ret = 0;
if (ret == 0) {
t->hide_transaction) {
if (ret < 0) {
return ret;