Mercurial > dovecot > core-2.2
changeset 223:ca6967899c05 HEAD
More cleanups. lib-storage should handle "out of disk space" conditions
properly.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 15 Sep 2002 09:30:29 +0300 |
parents | cf4d065f2f85 |
children | e8863d6088fe |
files | src/lib-index/mail-hash.c src/lib-index/mail-hash.h src/lib-index/mail-index-compress.c src/lib-index/mail-index-data.c src/lib-index/mail-index-data.h src/lib-index/mail-index.c src/lib-index/mail-lockdir.c src/lib-index/mail-modifylog.c src/lib-storage/index/index-copy.c src/lib-storage/index/index-fetch.c src/lib-storage/index/index-save.c src/lib-storage/index/index-search.c src/lib-storage/index/index-status.c src/lib-storage/index/index-storage.h src/lib-storage/index/index-sync.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/mbox/mbox-save.c src/lib/write-full.h |
diffstat | 18 files changed, 338 insertions(+), 175 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/mail-hash.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-hash.c Sun Sep 15 09:30:29 2002 +0300 @@ -57,6 +57,31 @@ unsigned int modified:1; }; +static void mail_hash_file_close(MailHash *hash) +{ + if (close(hash->fd) < 0) { + index_file_set_syscall_error(hash->index, + hash->filepath, "close()"); + } + hash->fd = -1; +} + +static int mail_hash_file_open(MailHash *hash) +{ + hash->fd = open(hash->filepath, O_RDWR); + if (hash->fd == -1) { + if (errno != ENOENT) { + index_file_set_syscall_error(hash->index, + hash->filepath, "open()"); + return FALSE; + } + + return mail_hash_rebuild(hash); + } + + return TRUE; +} + static int mmap_update_real(MailHash *hash) { i_assert(!hash->anon_mmap); @@ -91,7 +116,6 @@ } hash->header = hash->mmap_base; - hash->sync_id = hash->header->sync_id; hash->size = (hash->mmap_length - sizeof(MailHashHeader)) / sizeof(MailHashRecord); @@ -110,14 +134,26 @@ static int mmap_update(MailHash *hash) { if (hash->fd == -1) - return FALSE; + return hash->anon_mmap; + + /* see if it's been rebuilt */ + if (hash->header->indexid == hash->index->indexid) + return TRUE; - if (!hash->dirty_mmap) { - /* see if someone else modified it */ - if (hash->header->sync_id == hash->sync_id) - return TRUE; + if (hash->header->indexid != 0) { + /* index was just rebuilt. we should have noticed + this before at index->set_lock() though. */ + index_set_error(hash->index, "Warning: Inconsistency - Index " + "%s was rebuilt while we had it open", + hash->filepath); + hash->index->inconsistent = TRUE; + return FALSE; } + mail_hash_file_close(hash); + if (!mail_hash_file_open(hash)) + return FALSE; + return mmap_update_real(hash) && hash_verify_header(hash); } @@ -143,8 +179,6 @@ hash->fd = -1; hash->index = index; hash->filepath = i_strconcat(index->filepath, ".hash", NULL); - hash->dirty_mmap = TRUE; - index->hash = hash; return hash; } @@ -163,9 +197,8 @@ hash = mail_hash_new(index); - hash->fd = open(hash->filepath, O_RDWR); - if (hash->fd == -1) - return mail_hash_rebuild(hash); + if (!mail_hash_file_open(hash)) + return FALSE; if (!mmap_update_real(hash)) { /* mmap() failure is fatal */ @@ -174,11 +207,11 @@ } /* make sure the header looks fine */ - failed = TRUE; - if (hash_verify_header(hash)) { - if (hash->header->indexid == hash->index->indexid) - failed = FALSE; - else { + if (!hash_verify_header(hash)) + failed = TRUE; + else { + failed = hash->header->indexid != hash->index->indexid; + if (failed) { index_set_error(hash->index, "IndexID mismatch for hash file %s", hash->filepath); @@ -188,7 +221,6 @@ if (failed) { /* recreate it */ hash_munmap(hash); - hash->dirty_mmap = TRUE; return mail_hash_rebuild(hash); } @@ -255,7 +287,6 @@ /* setup header */ hdr = mmap_base; hdr->indexid = index->indexid; - hdr->sync_id = ioloop_time; hdr->used_records = count; } @@ -304,6 +335,28 @@ return !failed; } +/* set indexid to 0 in hash file */ +static int mail_hash_mark_deleted(MailHash *hash) +{ + MailIndexDataHeader hdr; + + if (hash->fd == -1) { + /* see if we can open it */ + hash->fd = open(hash->filepath, O_RDWR); + if (hash->fd == -1) + return TRUE; + } + + memset(&hdr, 0, sizeof(hdr)); + if (write_full(hash->fd, &hdr, sizeof(hdr)) < 0) { + index_file_set_syscall_error(hash->index, hash->filepath, + "write_full()"); + return FALSE; + } + + return TRUE; +} + int mail_hash_rebuild(MailHash *hash) { MailIndexHeader *index_header; @@ -338,6 +391,9 @@ failed = !hash_rebuild_to_file(hash->index, fd, path, hash_size); + if (!failed) + failed = !mail_hash_mark_deleted(hash); + if (!failed && rename(path, hash->filepath) < 0) { index_set_error(hash->index, "rename(%s, %s) failed: " "%m", path, hash->filepath); @@ -377,7 +433,6 @@ (void)close(hash->fd); hash->fd = fd; hash->anon_mmap = fd == -1; - hash->dirty_mmap = !hash->anon_mmap; return TRUE; }
--- a/src/lib-index/mail-hash.h Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-hash.h Sun Sep 15 09:30:29 2002 +0300 @@ -6,10 +6,7 @@ struct _MailHashHeader { unsigned int indexid; - unsigned int sync_id; unsigned int used_records; - - unsigned int alignment; }; struct _MailHashRecord {
--- a/src/lib-index/mail-index-compress.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-index-compress.c Sun Sep 15 09:30:29 2002 +0300 @@ -184,7 +184,11 @@ index_file_set_syscall_error(index, temppath, "close()"); if (!failed) { - /* now, rename the temp file to new data file */ + /* now, rename the temp file to new data file. but before that + reset indexid to make sure that other processes know the + data file is closed. */ + (void)mail_index_data_mark_deleted(index->data); + mail_index_data_free(index->data); datapath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
--- a/src/lib-index/mail-index-data.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-index-data.c Sun Sep 15 09:30:29 2002 +0300 @@ -69,10 +69,45 @@ return FALSE; } +static int data_file_reopen(MailIndexData *data) +{ + int fd; + + fd = open(data->filepath, O_RDWR); + if (fd == -1) + return index_data_set_syscall_error(data, "open()"); + + if (close(data->fd) < 0) + index_data_set_syscall_error(data, "close()"); + + data->fd = fd; + return TRUE; +} + static int mmap_update(MailIndexData *data, uoff_t pos, size_t size) { MailIndexDataHeader *hdr; + if (data->header != NULL && + data->header->indexid != data->index->indexid) { + if (data->header->indexid != 0) { + /* index was just rebuilt. we should have noticed + this before at index->set_lock() though. */ + index_set_error(data->index, + "Warning: Inconsistency - Index " + "%s was rebuilt while we had it open", + data->filepath); + data->index->inconsistent = TRUE; + return FALSE; + } + + /* data file was deleted, reopen it */ + if (!data_file_reopen(data)) + return FALSE; + + size = 0; + } + if (size != 0) { if (pos + size <= data->mmap_used_length) return TRUE; @@ -132,8 +167,7 @@ /* doesn't exist, rebuild the index */ INDEX_MARK_CORRUPTED(index); } - index_set_error(index, "Can't open index data %s: %m", path); - return FALSE; + return index_file_set_syscall_error(index, path, "open()"); } data = i_new(MailIndexData, 1); @@ -301,6 +335,18 @@ return TRUE; } +int mail_index_data_mark_deleted(MailIndexData *data) +{ + if (data->anon_mmap) + return TRUE; + + data->header->indexid = 0; + if (msync(data->mmap_base, 0, sizeof(MailIndexDataHeader)) < 0) + return index_data_set_syscall_error(data, "msync()"); + + return TRUE; +} + static int mail_index_data_grow(MailIndexData *data, size_t size) { void *base;
--- a/src/lib-index/mail-index-data.h Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-index-data.h Sun Sep 15 09:30:29 2002 +0300 @@ -10,6 +10,10 @@ /* Truncate the data file and update it's indexid */ int mail_index_data_reset(MailIndexData *data); +/* Set indexid to 0 to notify other processes using this file that they should + re-open it. */ +int mail_index_data_mark_deleted(MailIndexData *data); + /* Append new data at the end of the file. Returns the position in file where the data begins, or 0 if error occured. */ uoff_t mail_index_data_append(MailIndexData *data, const void *buffer,
--- a/src/lib-index/mail-index.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-index.c Sun Sep 15 09:30:29 2002 +0300 @@ -999,7 +999,7 @@ int mail_index_is_diskspace_error(MailIndex *index) { - return index->nodiskspace; + return !index->inconsistent && index->nodiskspace; } int mail_index_is_inconsistency_error(MailIndex *index)
--- a/src/lib-index/mail-lockdir.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-lockdir.c Sun Sep 15 09:30:29 2002 +0300 @@ -51,23 +51,19 @@ return FALSE; } -static int mail_index_unlock_dir(MailIndex *index, const char *path, +static int mail_index_unlock_dir(MailIndex *index, const char *private_path, const char *lockpath) { struct stat st, lockst; - if (stat(lockpath, &st) != 0) { - index_set_error(index, "stat() failed for lock file %s: %m", - lockpath); - return FALSE; - } + if (stat(lockpath, &st) < 0) + return index_file_set_syscall_error(index, lockpath, "stat()"); if (st.st_nlink > 1) { /* make sure we're really the one who's locked it */ - if (stat(path, &lockst) != 0) { - index_set_error(index, "stat() failed for lock file " - "%s: %m", path); - return FALSE; + if (stat(private_path, &lockst) < 0) { + return index_file_set_syscall_error(index, private_path, + "stat()"); } if (st.st_dev != lockst.st_dev || @@ -84,20 +80,22 @@ } /* first unlink the actual lock file */ - if (unlink(lockpath) == -1) { - index_set_error(index, "unlink() failed for lock file %s: %m", - lockpath); + if (unlink(lockpath) < 0) { + index_file_set_syscall_error(index, lockpath, "unlink()"); return FALSE; } - (void)unlink(path); + if (unlink(private_path) < 0) { + /* non-fatal */ + index_file_set_syscall_error(index, private_path, "unlink()"); + } return TRUE; } int mail_index_lock_dir(MailIndex *index, MailLockType lock_type) { struct stat st; - const char *path, *lockpath; + const char *private_path, *lockpath; int fd, orig_errno, first; time_t max_wait_time; @@ -108,33 +106,39 @@ /* use .dirlock.host.pid as our lock indicator file and .dirlock as the real lock */ - path = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX ".", - my_hostname, ".", my_pid, NULL); + private_path = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX ".", + my_hostname, ".", my_pid, NULL); lockpath = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX, NULL); if (lock_type == MAIL_LOCK_UNLOCK) - return mail_index_unlock_dir(index, path, lockpath); + return mail_index_unlock_dir(index, private_path, lockpath); - (void)unlink(path); - fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0660); + (void)unlink(private_path); + fd = open(private_path, O_RDWR | O_CREAT | O_EXCL, 0660); if (fd == -1) { - index_set_error(index, "Can't create lock file %s: %m", path); + if (errno == ENOSPC) + index->nodiskspace = TRUE; + index_file_set_syscall_error(index, private_path, "open()"); return FALSE; } /* try to link the file into lock file. */ first = TRUE; max_wait_time = time(NULL) + MAX_LOCK_WAIT_SECONDS; - while (link(path, lockpath) == -1) { + while (link(private_path, lockpath) < 0) { + if (errno == ENOSPC) + index->nodiskspace = TRUE; + if (errno != EEXIST) { orig_errno = errno; /* NFS may die and link() fail even if it really was created */ - if (stat(path, &st) == 0 && st.st_nlink == 2) + if (stat(private_path, &st) == 0 && st.st_nlink == 2) break; + errno = orig_errno; index_set_error(index, "link(%s, %s) lock failed: %m", - path, lockpath); + private_path, lockpath); return FALSE; }
--- a/src/lib-index/mail-modifylog.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-index/mail-modifylog.c Sun Sep 15 09:30:29 2002 +0300 @@ -31,22 +31,22 @@ unsigned int synced_id, mmaped_id; unsigned int modified:1; - unsigned int dirty_mmap:1; unsigned int second_log:1; }; static const unsigned int no_expunges[] = { 0 }; -static void modifylog_set_syscall_error(MailModifyLog *log, +static int modifylog_set_syscall_error(MailModifyLog *log, const char *function) { i_assert(function != NULL); index_set_error(log->index, "%s failed with modify log file %s: %m", function, log->filepath); + return FALSE; } -static void modifylog_set_corrupted(MailModifyLog *log) +static int modifylog_set_corrupted(MailModifyLog *log) { index_set_error(log->index, "Modify log %s is corrupted", log->filepath); @@ -54,18 +54,8 @@ /* make sure we don't get back here */ log->index->inconsistent = TRUE; (void)unlink(log->filepath); -} -/* Returns 1 = ok, 0 = failed to get the lock, -1 = error */ -static int mail_modifylog_try_lock(MailModifyLog *log, int lock_type) -{ - int ret; - - ret = file_try_lock(log->fd, lock_type); - if (ret == -1) - modifylog_set_syscall_error(log, "file_try_lock()"); - - return ret; + return FALSE; } static int mail_modifylog_wait_lock(MailModifyLog *log) @@ -82,46 +72,55 @@ int ret; /* try grabbing exclusive lock */ - ret = mail_modifylog_try_lock(log, F_WRLCK); - if (ret == -1) - return -1; + ret = file_try_lock(log->fd, F_WRLCK); + if (ret <= 0) { + if (ret < 0) + modifylog_set_syscall_error(log, "file_try_lock()"); + return ret; + } /* revert back to shared lock */ - switch (mail_modifylog_try_lock(log, F_RDLCK)) { - case 0: + ret = file_try_lock(log->fd, F_RDLCK); + if (ret < 0) { + modifylog_set_syscall_error(log, "file_try_lock()"); + return -1; + } + + if (ret == 0) { /* shouldn't happen */ index_set_error(log->index, "file_lock(F_WRLCK -> F_RDLCK) " "failed with file %s", log->filepath); - /* fall through */ - case -1: return -1; } - return ret == 0 ? 1 : 0; + return 1; } static int mmap_update(MailModifyLog *log) { unsigned int extra; - if (!log->dirty_mmap && log->mmaped_id == log->header->sync_id) + if (log->header != NULL && log->mmaped_id == log->header->sync_id) return TRUE; - if (log->mmap_base != NULL) - (void)munmap(log->mmap_base, log->mmap_length); + if (log->mmap_base != NULL) { + if (munmap(log->mmap_base, log->mmap_length) < 0) + modifylog_set_syscall_error(log, "munmap()"); + } + + log->header = NULL; log->mmap_base = mmap_rw_file(log->fd, &log->mmap_length); if (log->mmap_base == MAP_FAILED) { log->mmap_base = NULL; - log->header = NULL; - modifylog_set_syscall_error(log, "mmap()"); - return FALSE; + return modifylog_set_syscall_error(log, "mmap()"); } if (log->mmap_length < sizeof(ModifyLogHeader)) { - /* FIXME: we could do better.. */ + index_set_error(log->index, "Too small modify log %s", + log->filepath); (void)unlink(log->filepath); - i_panic("modify log corrupted"); + return FALSE; } extra = (log->mmap_length - sizeof(ModifyLogHeader)) % @@ -131,10 +130,10 @@ /* partial write or corrupted - truncate the file to valid length */ log->mmap_length -= extra; - (void)ftruncate(log->fd, (off_t)log->mmap_length); + if (ftruncate(log->fd, (off_t)log->mmap_length) < 0) + modifylog_set_syscall_error(log, "ftruncate()"); } - log->dirty_mmap = FALSE; log->header = log->mmap_base; log->mmaped_id = log->header->sync_id; return TRUE; @@ -147,7 +146,6 @@ log = i_new(MailModifyLog, 1); log->fd = -1; log->index = index; - log->dirty_mmap = TRUE; index->modifylog = log; return log; @@ -155,8 +153,6 @@ static void mail_modifylog_close(MailModifyLog *log) { - log->dirty_mmap = TRUE; - if (log->mmap_base != NULL) { munmap(log->mmap_base, log->mmap_length); log->mmap_base = NULL; @@ -180,14 +176,12 @@ hdr.indexid = log->index->indexid; if (write_full(fd, &hdr, sizeof(hdr)) < 0) { - index_set_error(log->index, "write() failed for modify " - "log %s: %m", path); + index_file_set_syscall_error(log->index, path, "write_full()"); return FALSE; } if (ftruncate(fd, sizeof(hdr)) < 0) { - index_set_error(log->index, "ftruncate() failed for modify " - "log %s: %m", path); + index_file_set_syscall_error(log->index, path, "ftruncate()"); return FALSE; } @@ -201,15 +195,17 @@ fd = open(path, O_RDWR | O_CREAT, 0660); if (fd == -1) { - index_set_error(log->index, "Error opening modify log " - "file %s: %m", path); + if (errno == ENOSPC) + log->index->nodiskspace = TRUE; + + index_file_set_syscall_error(log->index, path, "open()"); return FALSE; } ret = file_wait_lock(fd, F_WRLCK); if (ret == -1) { - index_set_error(log->index, "Error locking modify log " - "file %s: %m", path); + index_file_set_syscall_error(log->index, path, + "file_wait_lock()"); } if (ret == 1 && mail_modifylog_init_fd(log, fd, path)) { @@ -256,16 +252,15 @@ fd = open(path, O_RDWR); if (fd == -1) { if (errno != ENOENT) { - index_set_error(log->index, "Can't open modify log " - "file %s: %m", path); + index_file_set_syscall_error(log->index, path, + "open()"); } return -1; } ret = 1; if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { - index_set_error(log->index, "read() failed when for modify " - "log file %s: %m", path); + index_file_set_syscall_error(log->index, path, "read()"); ret = -1; } @@ -361,16 +356,12 @@ return TRUE; if (log->mmap_base != NULL) { - if (msync(log->mmap_base, log->mmap_length, MS_SYNC) < 0) { - modifylog_set_syscall_error(log, "msync()"); - return FALSE; - } + if (msync(log->mmap_base, log->mmap_length, MS_SYNC) < 0) + return modifylog_set_syscall_error(log, "msync()"); } - if (fsync(log->fd) < 0) { - modifylog_set_syscall_error(log, "fsync()"); - return FALSE; - } + if (fsync(log->fd) < 0) + return modifylog_set_syscall_error(log, "fsync()"); log->modified = FALSE; return TRUE; @@ -394,24 +385,20 @@ } } - if (lseek(log->fd, 0, SEEK_END) < 0) { - modifylog_set_syscall_error(log, "lseek()"); - return FALSE; - } + if (lseek(log->fd, 0, SEEK_END) < 0) + return modifylog_set_syscall_error(log, "lseek()"); - if (write_full(log->fd, rec, sizeof(ModifyLogRecord)) < 0) { - modifylog_set_syscall_error(log, "write_full()"); - return FALSE; + if (write_full(log->fd, rec, sizeof(ModifyLogRecord)) < 0) + return modifylog_set_syscall_error(log, "write_full()"); + + if (!external_change && log->header->sync_id == log->synced_id) { + log->synced_position += sizeof(ModifyLogRecord); + log->synced_id++; } log->header->sync_id++; log->modified = TRUE; - log->dirty_mmap = TRUE; - if (!external_change) { - log->synced_id = log->header->sync_id; - log->synced_position += sizeof(ModifyLogRecord); - } return TRUE; }
--- a/src/lib-storage/index/index-copy.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-copy.c Sun Sep 15 09:30:29 2002 +0300 @@ -11,12 +11,12 @@ typedef struct { Mailbox *dest; const char **custom_flags; -} CopyData; +} CopyContext; static int copy_func(MailIndex *index, MailIndexRecord *rec, unsigned int seq __attr_unused__, void *context) { - CopyData *cd = context; + CopyContext *ctx = context; IOBuffer *inbuf; int failed; @@ -25,9 +25,10 @@ return FALSE; /* save it in destination mailbox */ - failed = !cd->dest->save(cd->dest, rec->msg_flags, - cd->custom_flags, rec->internal_date, - inbuf, inbuf->size); + failed = !ctx->dest->save(ctx->dest, rec->msg_flags, + ctx->custom_flags, rec->internal_date, + inbuf, inbuf->size); + (void)close(inbuf->fd); io_buffer_destroy(inbuf); return !failed; @@ -37,7 +38,7 @@ const char *messageset, int uidset) { IndexMailbox *ibox = (IndexMailbox *) box; - CopyData cd; + CopyContext ctx; int failed; if (destbox->readonly) { @@ -52,11 +53,12 @@ if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) return mail_storage_set_index_error(ibox); - cd.custom_flags = mail_custom_flags_list_get(ibox->index->custom_flags); - cd.dest = destbox; + ctx.custom_flags = + mail_custom_flags_list_get(ibox->index->custom_flags); + ctx.dest = destbox; failed = index_messageset_foreach(ibox, messageset, uidset, - copy_func, &cd) <= 0; + copy_func, &ctx) <= 0; mail_custom_flags_list_unref(ibox->index->custom_flags);
--- a/src/lib-storage/index/index-fetch.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-fetch.c Sun Sep 15 09:30:29 2002 +0300 @@ -326,8 +326,8 @@ MailFetchBodyData *sect; int ret; - if (!ibox->index->sync(ibox->index)) - return mail_storage_set_index_error(ibox); + if (!index_storage_sync_if_possible(ibox)) + return FALSE; if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) return mail_storage_set_index_error(ibox);
--- a/src/lib-storage/index/index-save.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-save.c Sun Sep 15 09:30:29 2002 +0300 @@ -34,7 +34,7 @@ } } - return write_full(fd, data, size) < 0; + return write_full(fd, data, size) >= 0; } int index_storage_save_into_fd(MailStorage *storage, int fd, const char *path, @@ -60,9 +60,15 @@ size = (size_t)data_size; data_size -= size; - if (write_with_crlf(fd, data, size, &last_cr) != 0) { - mail_storage_set_critical(storage, "write() failed " - "for file %s: %m", path); + if (!write_with_crlf(fd, data, size, &last_cr)) { + if (errno == ENOSPC) { + mail_storage_set_error(storage, + "Not enough disk space"); + } else { + mail_storage_set_critical(storage, + "write() failed for " + "file %s: %m", path); + } return FALSE; }
--- a/src/lib-storage/index/index-search.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-search.c Sun Sep 15 09:30:29 2002 +0300 @@ -703,8 +703,8 @@ { IndexMailbox *ibox = (IndexMailbox *) box; - if (!ibox->index->sync(ibox->index)) - return mail_storage_set_index_error(ibox); + if (!index_storage_sync_if_possible(ibox)) + return FALSE; if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) return mail_storage_set_index_error(ibox);
--- a/src/lib-storage/index/index-status.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-status.c Sun Sep 15 09:30:29 2002 +0300 @@ -101,8 +101,8 @@ memset(status, 0, sizeof(MailboxStatus)); - if (!ibox->index->sync(ibox->index)) - return mail_storage_set_index_error(ibox); + if (!index_storage_sync_if_possible(ibox)) + return FALSE; if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) return mail_storage_set_index_error(ibox);
--- a/src/lib-storage/index/index-storage.h Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-storage.h Sun Sep 15 09:30:29 2002 +0300 @@ -22,12 +22,14 @@ extern ImapMessageCacheIface index_msgcache_iface; +int mail_storage_set_index_error(IndexMailbox *ibox); + IndexMailbox *index_storage_init(MailStorage *storage, Mailbox *box, MailIndex *index, const char *name, int readonly); void index_storage_close(Mailbox *box); -int mail_storage_set_index_error(IndexMailbox *ibox); +int index_storage_sync_if_possible(IndexMailbox *ibox); int index_mailbox_fix_custom_flags(IndexMailbox *ibox, MailFlags *flags, const char *custom_flags[]);
--- a/src/lib-storage/index/index-sync.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/index-sync.c Sun Sep 15 09:30:29 2002 +0300 @@ -2,9 +2,29 @@ #include "lib.h" #include "index-storage.h" +#include "mail-index-util.h" #include "mail-modifylog.h" #include "mail-custom-flags.h" +/* may leave the index locked */ +int index_storage_sync_if_possible(IndexMailbox *ibox) +{ + if (!ibox->index->sync(ibox->index)) { + if (!ibox->index->is_diskspace_error(ibox->index)) { + (void)ibox->index->set_lock(ibox->index, + MAIL_LOCK_UNLOCK); + return mail_storage_set_index_error(ibox); + } + + /* not enough disk space to sync. can't do much about it + though, giving error message would just make it impossible + to delete messages. */ + index_reset_error(ibox->index); + } + + return TRUE; +} + int index_storage_sync(Mailbox *box, unsigned int *messages, int expunge, MailExpungeFunc expunge_func, MailFlagUpdateFunc flag_func, @@ -25,8 +45,8 @@ *messages = 0; - if (!ibox->index->sync(ibox->index)) - return mail_storage_set_index_error(ibox); + if (!index_storage_sync_if_possible(ibox)) + return FALSE; if (!ibox->index->set_lock(ibox->index, expunge ? MAIL_LOCK_EXCLUSIVE : MAIL_LOCK_SHARED))
--- a/src/lib-storage/index/maildir/maildir-save.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/maildir/maildir-save.c Sun Sep 15 09:30:29 2002 +0300 @@ -26,10 +26,15 @@ path = t_strconcat(dir, "/", *fname, NULL); fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0660); if (fd == -1) { - /* don't bother checking if it was because file existed - - if that happens it's itself an error. */ - mail_storage_set_critical(storage, - "Can't create file %s: %m", path); + if (errno == ENOSPC) { + mail_storage_set_error(storage, + "Not enough disk space"); + } else { + /* don't bother checking if it was because file + existed - if that happens it's itself an error. */ + mail_storage_set_critical(storage, "Can't create file " + "%s: %m", path); + } } return fd; @@ -97,8 +102,15 @@ if (rename(tmp_path, new_path) == 0) failed = FALSE; else { - mail_storage_set_critical(box->storage, "rename(%s, %s) " - "failed: %m", tmp_path, new_path); + if (errno == ENOSPC) { + mail_storage_set_error(box->storage, + "Not enough disk space"); + } else { + mail_storage_set_critical(box->storage, + "rename(%s, %s) failed: %m", + tmp_path, new_path); + } + (void)unlink(tmp_path); failed = TRUE; }
--- a/src/lib-storage/index/mbox/mbox-save.c Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib-storage/index/mbox/mbox-save.c Sun Sep 15 09:30:29 2002 +0300 @@ -15,7 +15,45 @@ static char my_hostdomain[256] = ""; -static int write_from_line(MailStorage *storage, int fd, time_t internal_date) +static void set_error(MailStorage *storage, const char *mbox_path) +{ + if (errno == ENOSPC) + mail_storage_set_error(storage, "Not enough disk space"); + else { + mail_storage_set_critical(storage, "Error writing to " + "mbox file %s: %m", mbox_path); + } +} + +static int mbox_check_ending_lf(MailStorage *storage, int fd, off_t pos, + const char *mbox_path) +{ + char ch; + + if (pos == 0) + return TRUE; + + do { + if (lseek(fd, 0, pos-1) < 0) + break; + + if (read(fd, &ch, 1) != 1) + break; + + if (ch != '\n') { + if (write_full(fd, &ch, 1) < 0) + break; + } + + return TRUE; + } while (0); + + set_error(storage, mbox_path); + return FALSE; +} + +static int write_from_line(MailStorage *storage, int fd, const char *mbox_path, + time_t internal_date) { const char *sender, *line, *name; size_t len; @@ -41,7 +79,12 @@ line = mbox_from_create(sender, internal_date); len = strlen(line); - return write_full(fd, line, len) < 0; + if (write_full(fd, line, len) < 0) { + set_error(storage, mbox_path); + return FALSE; + } + + return TRUE; } int mbox_storage_save(Mailbox *box, MailFlags flags, const char *custom_flags[], @@ -49,6 +92,7 @@ { IndexMailbox *ibox = (IndexMailbox *) box; off_t pos; + const char *mbox_path; int fd, failed; if (box->readonly) { @@ -75,39 +119,19 @@ failed = FALSE; pos = lseek(fd, 0, SEEK_END); - if (pos == -1) { + if (pos < 0) { mail_storage_set_critical(box->storage, "lseek() failed for mbox file %s: %m", ibox->index->mbox_path); failed = TRUE; } else { - if (pos > 0) { - /* make sure the file ends with \n */ - if (lseek(fd, 0, pos-1) != pos-1) - failed = TRUE; - else { - char ch; + mbox_path = ibox->index->mbox_path; - if (read(fd, &ch, 1) != 1) - failed = TRUE; - else if (ch != '\n') { - if (write_full(fd, &ch, 1) < 0) - failed = TRUE; - } - } - } - - if (failed) { - /* don't bother separating the errors, it's very - unlikely that this will happen */ - mail_storage_set_critical(box->storage, - "Error appending LF to mbox " - "file %s: %m", - ibox->index->mbox_path); - } else if (!write_from_line(box->storage, fd, internal_date) || - !index_storage_save_into_fd(box->storage, fd, - ibox->index->mbox_path, - data, data_size)) { + if (!mbox_check_ending_lf(box->storage, fd, pos, mbox_path) || + !write_from_line(box->storage, fd, mbox_path, + internal_date) || + !index_storage_save_into_fd(box->storage, fd, mbox_path, + data, data_size)) { /* failed, truncate file back to original size */ (void)ftruncate(fd, pos); failed = TRUE;
--- a/src/lib/write-full.h Sat Sep 14 14:09:42 2002 +0300 +++ b/src/lib/write-full.h Sun Sep 15 09:30:29 2002 +0300 @@ -2,7 +2,7 @@ #define __WRITE_FULL_H /* Write data into file. Returns -1 if error occured, or 0 if all was ok. - If there's not enough space in device -1 with ENOSPC is returned, and + If there's not enough space in device, -1 with ENOSPC is returned, and it's unspecified how much data was actually written. */ int write_full(int fd, const void *data, size_t size);