[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