[dovecot-cvs] dovecot/src/lib-storage/subscription-file
subscription-file.c,1.19,1.20
cras at procontrol.fi
cras at procontrol.fi
Sun Jul 6 04:29:03 EEST 2003
Update of /home/cvs/dovecot/src/lib-storage/subscription-file
In directory danu:/tmp/cvs-serv27144/lib-storage/subscription-file
Modified Files:
subscription-file.c
Log Message:
NFS-safe subscription file
Index: subscription-file.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/subscription-file/subscription-file.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- subscription-file.c 23 May 2003 14:40:50 -0000 1.19
+++ subscription-file.c 6 Jul 2003 00:29:00 -0000 1.20
@@ -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);
More information about the dovecot-cvs
mailing list