Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1598:d45c613e3b15 HEAD
NFS-safe subscription file
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 06 Jul 2003 03:29:00 +0300 |
parents | 9f503b7851ab |
children | 4c4d0d771350 |
files | src/lib-storage/subscription-file/subscription-file.c |
diffstat | 1 files changed, 75 insertions(+), 95 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/subscription-file/subscription-file.c Sat Jul 05 23:33:18 2003 +0300 +++ b/src/lib-storage/subscription-file/subscription-file.c Sun Jul 06 03:29:00 2003 +0300 @@ -3,8 +3,7 @@ #include "lib.h" #include "istream.h" #include "ostream.h" -#include "file-lock.h" -#include "write-full.h" +#include "file-dotlock.h" #include "mail-storage.h" #include "subscription-file.h" @@ -14,6 +13,9 @@ #define SUBSCRIPTION_FILE_NAME ".subscriptions" #define MAX_MAILBOX_LENGTH PATH_MAX +#define SUBSCRIPTION_FILE_LOCK_TIMEOUT 120 +#define SUBSCRIPTION_FILE_STALE_TIMEOUT 30 + struct subsfile_list_context { pool_t pool; @@ -25,7 +27,7 @@ }; static int subsfile_set_syscall_error(struct mail_storage *storage, - const char *path, const char *function) + const char *function, const char *path) { i_assert(function != NULL); @@ -35,39 +37,10 @@ } mail_storage_set_critical(storage, - "%s failed with subscription file %s: %m", - function, path); + "%s failed with subscription file %s: %m", function, path); return FALSE; } -static int subscription_open(struct mail_storage *storage, int update, - const char **path) -{ - int fd; - - *path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL); - - fd = update ? open(*path, O_RDWR | O_CREAT, 0660) : - open(*path, O_RDONLY); - if (fd == -1) { - if (update || errno != ENOENT) { - subsfile_set_syscall_error(storage, "open()", *path); - return -1; - } - - return -1; - } - - /* FIXME: we should work without locking, rename() would be easiest - but .lock would work too */ - if (file_wait_lock(fd, update ? F_WRLCK : F_RDLCK) <= 0) { - subsfile_set_syscall_error(storage, "file_wait_lock()", *path); - (void)close(fd); - return -1; - } - return fd; -} - static const char *next_line(struct mail_storage *storage, const char *path, struct istream *input, int *failed) { @@ -93,84 +66,86 @@ return line; } -static int stream_cut(struct mail_storage *storage, const char *path, - struct istream *input, uoff_t count) -{ - struct ostream *output; - int fd, failed; - - fd = i_stream_get_fd(input); - i_assert(fd != -1); - - output = o_stream_create_file(fd, default_pool, 4096, FALSE); - if (o_stream_seek(output, input->start_offset + input->v_offset) < 0) { - failed = TRUE; - errno = output->stream_errno; - subsfile_set_syscall_error(storage, "o_stream_seek()", path); - } else { - i_stream_skip(input, count); - failed = o_stream_send_istream(output, input) < 0; - if (failed) { - errno = output->stream_errno; - subsfile_set_syscall_error(storage, - "o_stream_send_istream()", - path); - } - } - - if (!failed) { - if (ftruncate(fd, output->offset) < 0) { - subsfile_set_syscall_error(storage, "ftruncate()", - path); - failed = TRUE; - } - } - - o_stream_unref(output); - return !failed; -} - int subsfile_set_subscribed(struct mail_storage *storage, const char *name, int set) { const char *path, *line; struct istream *input; - uoff_t offset; - int fd, failed; + struct ostream *output; + int fd_in, fd_out, found, failed = FALSE; if (strcasecmp(name, "INBOX") == 0) name = "INBOX"; - fd = subscription_open(storage, TRUE, &path); - if (fd == -1) + path = t_strconcat(storage->control_dir != NULL ? + storage->control_dir : storage->dir, + "/" SUBSCRIPTION_FILE_NAME, NULL); + /* FIXME: set lock notification callback */ + fd_out = file_dotlock_open(path, NULL, SUBSCRIPTION_FILE_LOCK_TIMEOUT, + SUBSCRIPTION_FILE_STALE_TIMEOUT, NULL, NULL); + if (fd_out == -1) { + if (errno == EAGAIN) { + mail_storage_set_error(storage, + "Timeout waiting for subscription file lock"); + } else { + subsfile_set_syscall_error(storage, + "file_dotlock_open()", path); + } return FALSE; + } - input = i_stream_create_file(fd, default_pool, - MAX_MAILBOX_LENGTH, FALSE); - do { - offset = input->v_offset; - line = next_line(storage, path, input, &failed); - } while (line != NULL && strcmp(line, name) != 0); + fd_in = open(path, O_RDONLY); + if (fd_in == -1 && errno != ENOENT) { + subsfile_set_syscall_error(storage, "open()", path); + file_dotlock_delete(path, fd_out); + return FALSE; + } - if (!failed) { - if (set && line == NULL) { - /* add subscription. we're at EOF so just write it */ - write_full(fd, t_strconcat(name, "\n", NULL), - strlen(name)+1); - } else if (!set && line != NULL) { - /* remove subcription. */ - uoff_t size = input->v_offset - offset; - i_stream_seek(input, offset); - if (!stream_cut(storage, path, input, size)) + input = i_stream_create_file(fd_in, default_pool, + MAX_MAILBOX_LENGTH, TRUE); + output = o_stream_create_file(fd_out, default_pool, + MAX_MAILBOX_LENGTH, FALSE); + found = FALSE; + while ((line = next_line(storage, path, input, &failed)) != NULL) { + if (strcmp(line, name) == 0) { + found = TRUE; + if (set) + break; + } else { + if (o_stream_send_str(output, line) < 0 || + o_stream_send(output, "\n", 1) < 0) { + subsfile_set_syscall_error(storage, "write()", + path); failed = TRUE; + break; + } + } + } + + if (!failed && set && !found) { + /* append subscription */ + line = t_strconcat(name, "\n", NULL); + if (o_stream_send_str(output, line) < 0) { + subsfile_set_syscall_error(storage, "write()", path); + failed = TRUE; } } i_stream_unref(input); + o_stream_unref(output); - if (close(fd) < 0) { - subsfile_set_syscall_error(storage, "close()", path); - failed = TRUE; + if (failed || (set && found) || (!set && !found)) { + if (file_dotlock_delete(path, fd_out) < 0) { + subsfile_set_syscall_error(storage, + "file_dotlock_delete()", path); + failed = TRUE; + } + } else { + if (file_dotlock_replace(path, fd_out, TRUE) < 0) { + subsfile_set_syscall_error(storage, + "file_dotlock_replace()", path); + failed = TRUE; + } } return !failed; } @@ -183,9 +158,14 @@ const char *path; int fd; - fd = subscription_open(storage, FALSE, &path); - if (fd == -1 && errno != ENOENT) + path = t_strconcat(storage->control_dir != NULL ? + storage->control_dir : storage->dir, + "/" SUBSCRIPTION_FILE_NAME, NULL); + fd = open(path, O_RDONLY); + if (fd == -1 && errno != ENOENT) { + subsfile_set_syscall_error(storage, "open()", path); return NULL; + } pool = pool_alloconly_create("subsfile_list", MAX_MAILBOX_LENGTH+1024);