[dovecot-cvs] dovecot/src/lib file-dotlock.c, 1.22, 1.23 file-dotlock.h, 1.7, 1.8

cras at dovecot.org cras at dovecot.org
Sun Jan 16 21:18:26 EET 2005


Update of /var/lib/cvs/dovecot/src/lib
In directory talvi:/tmp/cvs-serv4353/lib

Modified Files:
	file-dotlock.c file-dotlock.h 
Log Message:
Changed dotlocking API.



Index: file-dotlock.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/file-dotlock.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- file-dotlock.c	6 Jan 2005 19:08:49 -0000	1.22
+++ file-dotlock.c	16 Jan 2005 19:18:23 -0000	1.23
@@ -19,10 +19,20 @@
 /* 0.1 .. 0.2msec */
 #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
 
+struct dotlock {
+	struct dotlock_settings settings;
+
+	dev_t dev;
+	ino_t ino;
+	time_t mtime;
+
+	char *path;
+	int fd;
+};
+
 struct lock_info {
+	const struct dotlock_settings *set;
 	const char *path, *lock_path, *temp_path;
-	unsigned int stale_timeout;
-	unsigned int immediate_stale_timeout;
 	int fd;
 
 	dev_t dev;
@@ -38,6 +48,20 @@
 	time_t last_pid_check;
 };
 
+static struct dotlock *
+file_dotlock_alloc(const struct dotlock_settings *settings)
+{
+	struct dotlock *dotlock;
+
+	dotlock = i_new(struct dotlock, 1);
+	dotlock->settings = *settings;
+	if (dotlock->settings.lock_suffix == NULL)
+		dotlock->settings.lock_suffix = DEFAULT_LOCK_SUFFIX;
+	dotlock->fd = -1;
+
+	return dotlock;
+}
+
 static pid_t read_local_pid(const char *lock_path)
 {
 	char buf[512], *host;
@@ -76,6 +100,9 @@
 
 static int check_lock(time_t now, struct lock_info *lock_info)
 {
+	time_t immediate_stale_timeout =
+		lock_info->set->immediate_stale_timeout;
+	time_t stale_timeout = lock_info->set->stale_timeout;
 	struct stat st;
 	pid_t pid;
 
@@ -87,9 +114,9 @@
 		return 1;
 	}
 
-	if (lock_info->immediate_stale_timeout != 0 &&
-	    now > st.st_mtime + (time_t)lock_info->immediate_stale_timeout &&
-	    now > st.st_ctime + (time_t)lock_info->immediate_stale_timeout) {
+	if (lock_info->set->immediate_stale_timeout != 0 &&
+	    now > st.st_mtime + immediate_stale_timeout &&
+	    now > st.st_ctime + immediate_stale_timeout) {
 		/* old lock file */
 		if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
 			i_error("unlink(%s) failed: %m", lock_info->lock_path);
@@ -147,7 +174,7 @@
 		return 1;
 	}
 
-	if (lock_info->stale_timeout == 0) {
+	if (stale_timeout == 0) {
 		/* no change checking */
 		return 0;
 	}
@@ -171,7 +198,7 @@
 		}
 	}
 
-	if (now > lock_info->last_change + (time_t)lock_info->stale_timeout) {
+	if (now > lock_info->last_change + stale_timeout) {
 		/* no changes for a while, assume stale lock */
 		if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
 			i_error("unlink(%s) failed: %m", lock_info->lock_path);
@@ -236,9 +263,9 @@
 	return fd;
 }
 
-static int try_create_lock(struct lock_info *lock_info, const char *temp_prefix,
-			   int write_pid)
+static int try_create_lock(struct lock_info *lock_info, int write_pid)
 {
+	const char *temp_prefix = lock_info->set->temp_prefix;
 	const char *str, *p;
 
 	if (lock_info->temp_path == NULL) {
@@ -280,15 +307,10 @@
 	return 1;
 }
 
-static int
-dotlock_create(const char *path, const char *temp_prefix,
-	       const char *lock_suffix, int checkonly, int *fd,
-	       unsigned int timeout, unsigned int stale_timeout,
-	       unsigned int immediate_stale_timeout, int write_pid,
-	       int (*callback)(unsigned int secs_left, int stale,
-			       void *context),
-	       void *context)
+static int dotlock_create(const char *path, struct dotlock *dotlock,
+			  enum dotlock_create_flags flags, int write_pid)
 {
+	const struct dotlock_settings *set = &dotlock->settings;
 	const char *lock_path;
         struct lock_info lock_info;
 	unsigned int stale_notify_threshold;
@@ -298,15 +320,15 @@
 
 	now = time(NULL);
 
-	lock_path = t_strconcat(path, lock_suffix, NULL);
-	stale_notify_threshold = stale_timeout / 2;
-	max_wait_time = now + timeout;
+	lock_path = t_strconcat(path, set->lock_suffix, NULL);
+	stale_notify_threshold = set->stale_timeout / 2;
+	max_wait_time = (flags & DOTLOCK_CREATE_FLAG_NONBLOCK) != 0 ? 0 :
+		now + set->timeout;
 
 	memset(&lock_info, 0, sizeof(lock_info));
 	lock_info.path = path;
+	lock_info.set = set;
 	lock_info.lock_path = lock_path;
-	lock_info.stale_timeout = stale_timeout;
-	lock_info.immediate_stale_timeout = immediate_stale_timeout;
 	lock_info.last_change = now;
 	lock_info.fd = -1;
 
@@ -323,17 +345,16 @@
 			break;
 
 		if (ret == 1) {
-			if (checkonly)
+			if ((flags & DOTLOCK_CREATE_FLAG_CHECKONLY) != 0)
 				break;
 
-			ret = try_create_lock(&lock_info, temp_prefix,
-					      write_pid);
+			ret = try_create_lock(&lock_info, write_pid);
 			if (ret != 0)
 				break;
 		}
 
 		do_wait = TRUE;
-		if (last_notify != now && callback != NULL) {
+		if (last_notify != now && set->callback != NULL) {
 			last_notify = now;
 			change_secs = now - lock_info.last_change;
 			wait_left = max_wait_time - now;
@@ -341,14 +362,17 @@
 			t_push();
 			if (change_secs >= stale_notify_threshold &&
 			    change_secs <= wait_left) {
-				if (!callback(stale_timeout < change_secs ? 0 :
-					      stale_timeout - change_secs,
-					      TRUE, context)) {
+				unsigned int secs_left =
+					set->stale_timeout < change_secs ?
+					0 : set->stale_timeout - change_secs;
+				if (!set->callback(secs_left, TRUE,
+						   set->context)) {
 					/* we don't want to override */
 					lock_info.last_change = now;
 				}
 			} else {
-				(void)callback(wait_left, FALSE, context);
+				(void)set->callback(wait_left, FALSE,
+						    set->context);
 			}
 			t_pop();
 		}
@@ -359,48 +383,71 @@
 	if (ret <= 0 && lock_info.fd != -1) {
 		int old_errno = errno;
 
-		(void)close(lock_info.fd);
-		lock_info.fd = -1;
+		if (close(lock_info.fd) < 0)
+			i_error("close(dotlock) failed: %m");
 		errno = old_errno;
+	} else {
+		dotlock->path = i_strdup(path);
+		dotlock->fd = lock_info.fd;
 	}
-	*fd = lock_info.fd;
 
 	if (ret == 0)
 		errno = EAGAIN;
 	return ret;
 }
 
-int file_lock_dotlock(const char *path, const char *temp_prefix, int checkonly,
-		      unsigned int timeout, unsigned int stale_timeout,
-		      unsigned int immediate_stale_timeout,
-		      int (*callback)(unsigned int secs_left, int stale,
-				      void *context),
-		      void *context, struct dotlock *dotlock_r)
+static void file_dotlock_free(struct dotlock *dotlock)
 {
+	int old_errno;
+
+	if (dotlock->fd != -1) {
+		old_errno = errno;
+		if (close(dotlock->fd) < 0)
+			i_error("close(%s) failed: %m", dotlock->path);
+		dotlock->fd = -1;
+		errno = old_errno;
+	}
+
+	i_free(dotlock->path);
+	i_free(dotlock);
+}
+
+int file_dotlock_create(const struct dotlock_settings *set, const char *path,
+			enum dotlock_create_flags flags,
+			struct dotlock **dotlock_r)
+{
+	struct dotlock *dotlock;
 	const char *lock_path;
 	struct stat st;
 	int fd, ret;
 
-	lock_path = t_strconcat(path, DEFAULT_LOCK_SUFFIX, NULL);
+	*dotlock_r = NULL;
 
-	ret = dotlock_create(path, temp_prefix, DEFAULT_LOCK_SUFFIX,
-			     checkonly, &fd, timeout, stale_timeout,
-			     immediate_stale_timeout, TRUE, callback, context);
-	if (ret <= 0 || checkonly)
+	dotlock = file_dotlock_alloc(set);
+	lock_path = t_strconcat(path, dotlock->settings.lock_suffix, NULL);
+
+	ret = dotlock_create(path, dotlock, flags, TRUE);
+	if (ret <= 0 || (flags & DOTLOCK_CREATE_FLAG_CHECKONLY) != 0) {
+		i_free(dotlock);
 		return ret;
+	}
 
 	/* save the inode info after writing */
-	if (fstat(fd, &st) < 0) {
+	if (fstat(dotlock->fd, &st) < 0) {
 		i_error("fstat(%s) failed: %m", lock_path);
-		(void)close(fd);
+                file_dotlock_free(dotlock);
 		return -1;
 	}
 
-	dotlock_r->dev = st.st_dev;
-	dotlock_r->ino = st.st_ino;
+	dotlock->dev = st.st_dev;
+	dotlock->ino = st.st_ino;
+
+	fd = dotlock->fd;
+	dotlock->fd = -1;
 
 	if (close(fd) < 0) {
-		i_error("fstat(%s) failed: %m", lock_path);
+		i_error("close(%s) failed: %m", lock_path);
+		file_dotlock_free(dotlock);
 		return -1;
 	}
 
@@ -408,34 +455,43 @@
 	   fstat() call. Check again to avoid "dotlock was modified" errors. */
 	if (stat(lock_path, &st) < 0) {
 		i_error("stat(%s) failed: %m", lock_path);
+                file_dotlock_free(dotlock);
 		return -1;
 	}
 	/* extra sanity check won't hurt.. */
-	if (st.st_dev != dotlock_r->dev ||
-	    st.st_ino != dotlock_r->ino) {
+	if (st.st_dev != dotlock->dev || st.st_ino != dotlock->ino) {
 		i_error("dotlock %s was immediately recreated under us",
 			lock_path);
+                file_dotlock_free(dotlock);
 		return -1;
 	}
-	dotlock_r->mtime = st.st_mtime;
+	dotlock->mtime = st.st_mtime;
+
+	*dotlock_r = dotlock;
 	return 1;
 }
 
-static int dotlock_delete(const char *path, const char *lock_suffix,
-			  const struct dotlock *dotlock, int check_mtime)
+int file_dotlock_delete(struct dotlock **dotlock_p)
 {
+	struct dotlock *dotlock;
 	const char *lock_path;
         struct stat st;
 
-	lock_path = t_strconcat(path, lock_suffix, NULL);
+	dotlock = *dotlock_p;
+	*dotlock_p = NULL;
+
+	lock_path = t_strconcat(dotlock->path,
+				dotlock->settings.lock_suffix, NULL);
 
 	if (lstat(lock_path, &st) < 0) {
 		if (errno == ENOENT) {
 			i_warning("Our dotlock file %s was deleted", lock_path);
+			file_dotlock_free(dotlock);
 			return 0;
 		}
 
 		i_error("lstat(%s) failed: %m", lock_path);
+		file_dotlock_free(dotlock);
 		return -1;
 	}
 
@@ -443,10 +499,11 @@
 	    !CMP_DEV_T(dotlock->dev, st.st_dev)) {
 		i_warning("Our dotlock file %s was overridden", lock_path);
 		errno = EEXIST;
+		file_dotlock_free(dotlock);
 		return 0;
 	}
 
-	if (dotlock->mtime != st.st_mtime && check_mtime) {
+	if (dotlock->mtime != st.st_mtime && dotlock->fd == -1) {
 		i_warning("Our dotlock file %s was modified (%s vs %s), "
 			  "assuming it wasn't overridden", lock_path,
 			  dec2str(dotlock->mtime), dec2str(st.st_mtime));
@@ -455,72 +512,66 @@
 	if (unlink(lock_path) < 0) {
 		if (errno == ENOENT) {
 			i_warning("Our dotlock file %s was deleted", lock_path);
+			file_dotlock_free(dotlock);
 			return 0;
 		}
 
 		i_error("unlink(%s) failed: %m", lock_path);
+		file_dotlock_free(dotlock);
 		return -1;
 	}
 
+	file_dotlock_free(dotlock);
 	return 1;
 }
 
-int file_unlock_dotlock(const char *path, const struct dotlock *dotlock)
-{
-	return dotlock_delete(path, DEFAULT_LOCK_SUFFIX, dotlock, TRUE);
-}
-
-int file_dotlock_open(const char *path,
-		      const char *temp_prefix, const char *lock_suffix,
-		      unsigned int timeout, unsigned int stale_timeout,
-		      unsigned int immediate_stale_timeout,
-		      int (*callback)(unsigned int secs_left, int stale,
-				      void *context),
-		      void *context)
+int file_dotlock_open(const struct dotlock_settings *set, const char *path,
+		      enum dotlock_create_flags flags,
+		      struct dotlock **dotlock_r)
 {
-	int ret, fd;
+	struct dotlock *dotlock;
+	int ret;
 
-	if (lock_suffix == NULL)
-		lock_suffix = DEFAULT_LOCK_SUFFIX;
+	dotlock = file_dotlock_alloc(set);
 
-	ret = dotlock_create(path, temp_prefix, lock_suffix, FALSE, &fd,
-			     timeout, stale_timeout, immediate_stale_timeout,
-			     FALSE, callback, context);
-	if (ret <= 0)
+	ret = dotlock_create(path, dotlock, flags, FALSE);
+	if (ret <= 0) {
+		file_dotlock_free(dotlock);
+		*dotlock_r = NULL;
 		return -1;
-	return fd;
+	}
+
+	*dotlock_r = dotlock;
+	return dotlock->fd;
 }
 
-int file_dotlock_replace(const char *path, const char *lock_suffix,
-			 int fd, int verify_owner)
+int file_dotlock_replace(struct dotlock **dotlock_p,
+			 enum dotlock_replace_flags flags)
 {
+	struct dotlock *dotlock;
 	struct stat st, st2;
 	const char *lock_path;
-	int old_errno;
+	int fd;
 
-	if (lock_suffix == NULL)
-		lock_suffix = DEFAULT_LOCK_SUFFIX;
+	dotlock = *dotlock_p;
+	*dotlock_p = NULL;
 
-	lock_path = t_strconcat(path, lock_suffix, NULL);
-	if (verify_owner) {
+	fd = dotlock->fd;
+	if ((flags & DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) != 0)
+		dotlock->fd = -1;
+
+	lock_path = t_strconcat(dotlock->path,
+				dotlock->settings.lock_suffix, NULL);
+	if ((flags & DOTLOCK_REPLACE_FLAG_VERIFY_OWNER) != 0) {
 		if (fstat(fd, &st) < 0) {
-			old_errno = errno;
 			i_error("fstat(%s) failed: %m", lock_path);
-			(void)close(fd);
-			errno = old_errno;
-			return -1;
-		}
-	}
-	if (fd != -1) {
-		if (close(fd) < 0) {
-			i_error("close(%s) failed: %m", lock_path);
+			file_dotlock_free(dotlock);
 			return -1;
 		}
-	}
 
-	if (verify_owner) {
 		if (lstat(lock_path, &st2) < 0) {
 			i_error("lstat(%s) failed: %m", lock_path);
+			file_dotlock_free(dotlock);
 			return -1;
 		}
 
@@ -529,44 +580,16 @@
 			i_warning("Our dotlock file %s was overridden",
 				  lock_path);
 			errno = EEXIST;
+			file_dotlock_free(dotlock);
 			return 0;
 		}
 	}
 
-	if (rename(lock_path, path) < 0) {
-		i_error("rename(%s, %s) failed: %m", lock_path, path);
+	if (rename(lock_path, dotlock->path) < 0) {
+		i_error("rename(%s, %s) failed: %m", lock_path, dotlock->path);
+		file_dotlock_free(dotlock);
 		return -1;
 	}
+	file_dotlock_free(dotlock);
 	return 1;
 }
-
-int file_dotlock_delete(const char *path, const char *lock_suffix, int fd)
-{
-	struct dotlock dotlock;
-	struct stat st;
-	int old_errno;
-
-	if (lock_suffix == NULL)
-		lock_suffix = DEFAULT_LOCK_SUFFIX;
-
-	if (fstat(fd, &st) < 0) {
-		old_errno = errno;
-		i_error("fstat(%s) failed: %m",
-			t_strconcat(path, lock_suffix, NULL));
-		(void)close(fd);
-		errno = old_errno;
-		return -1;
-	}
-
-	if (close(fd) < 0) {
-		i_error("close(%s) failed: %m",
-			t_strconcat(path, lock_suffix, NULL));
-		return -1;
-	}
-
-	dotlock.dev = st.st_dev;
-	dotlock.ino = st.st_ino;
-	dotlock.mtime = st.st_mtime;
-
-	return dotlock_delete(path, lock_suffix, &dotlock, FALSE);
-}

Index: file-dotlock.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/file-dotlock.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- file-dotlock.h	28 Jun 2004 16:44:38 -0000	1.7
+++ file-dotlock.h	16 Jan 2005 19:18:23 -0000	1.8
@@ -4,55 +4,65 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-struct dotlock {
-	dev_t dev;
-	ino_t ino;
-	time_t mtime;
-};
+struct dotlock;
 
-/* Create dotlock. Returns 1 if successful, 0 if timeout or -1 if error.
-   When returning 0, errno is also set to EAGAIN.
+struct dotlock_settings {
+	/* Dotlock files are created by first creating a temp file and then
+	   link()ing it to the dotlock. temp_prefix specifies the prefix to
+	   use for temp files. It may contain a full path. Default is
+	   ".temp.hostname.pid.". */
+	const char *temp_prefix;
+	/* Use this suffix for dotlock filenames. Default is ".lock". */
+	const char *lock_suffix;
 
-   If file specified in path doesn't change in stale_timeout seconds and it's
-   still locked, override the lock file.
+	/* Abort after this many seconds. */
+	unsigned int timeout;
+	/* If file specified in path doesn't change in stale_timeout seconds
+	   and it's still locked, override the lock file. */
+	unsigned int stale_timeout;
+	/* If file is older than this, override the lock immediately. */
+	unsigned int immediate_stale_timeout;
 
-   If checkonly is TRUE, we don't actually create the lock file, only make
-   sure that it doesn't exist. This is racy, so you shouldn't rely on it.
+	/* Callback is called once in a while. stale is set to TRUE if stale
+	   lock is detected and will be overridden in secs_left. If callback
+	   returns FALSE then, the lock will not be overridden. */
+	int (*callback)(unsigned int secs_left, int stale, void *context);
+	void *context;
+};
 
-   Dotlock files are created by first creating a temp file and then link()ing
-   it to the dotlock. temp_prefix specifies the prefix to use for temp files.
-   It may contain a full path. If it's NULL, ".temp.hostname.pid." is used
+enum dotlock_create_flags {
+	/* If lock already exists, fail immediately */
+	DOTLOCK_CREATE_FLAG_NONBLOCK		= 0x01,
+	/* Don't actually create the lock file, only make sure it doesn't
+	   exist. This is racy, so you shouldn't rely on it much. */
+	DOTLOCK_CREATE_FLAG_CHECKONLY		= 0x02
+};
 
-   callback is called once in a while. stale is set to TRUE if stale lock is
-   detected and will be overridden in secs_left. If callback returns FALSE
-   then, the lock will not be overridden. */
-int file_lock_dotlock(const char *path, const char *temp_prefix, int checkonly,
-		      unsigned int timeout, unsigned int stale_timeout,
-		      unsigned int immediate_stale_timeout,
-		      int (*callback)(unsigned int secs_left, int stale,
-				      void *context),
-		      void *context, struct dotlock *dotlock_r);
+enum dotlock_replace_flags {
+	/* Check that lock file hasn't been overwritten before renaming. */
+	DOTLOCK_REPLACE_FLAG_VERIFY_OWNER	= 0x01,
+	/* Don't close the file descriptor. */
+	DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD	= 0x02
+};
+
+/* Create dotlock. Returns 1 if successful, 0 if timeout or -1 if error.
+   When returning 0, errno is also set to EAGAIN. */
+int file_dotlock_create(const struct dotlock_settings *set, const char *path,
+			enum dotlock_create_flags flags,
+			struct dotlock **dotlock_r);
 
 /* Delete the dotlock file. Returns 1 if successful, 0 if the file was already
    been deleted or reused by someone else, -1 if error. */
-int file_unlock_dotlock(const char *path, const struct dotlock *dotlock);
+int file_dotlock_delete(struct dotlock **dotlock);
 
 /* Use dotlock as the new content for file. This provides read safety without
-   locks, but not very good for large files. Returns fd for lock file.
+   locks, but it's not very good for large files. Returns fd for lock file.
    If locking timed out, returns -1 and errno = EAGAIN. */
-int file_dotlock_open(const char *path,
-		      const char *temp_prefix, const char *lock_suffix,
-		      unsigned int timeout, unsigned int stale_timeout,
-		      unsigned int immediate_stale_timeout,
-		      int (*callback)(unsigned int secs_left, int stale,
-				      void *context),
-		      void *context);
-/* Replaces path with path.lock file. If verify_owner is TRUE, it checks that
-   lock file hasn't been overwritten before renaming. Closes given fd, unless
-   it's given as -1 in which case verify_owner must be FALSE. */
-int file_dotlock_replace(const char *path, const char *lock_suffix,
-			 int fd, int verify_owner);
-/* Like file_unlock_dotlock(). Closes given fd. */
-int file_dotlock_delete(const char *path, const char *lock_suffix, int fd);
+int file_dotlock_open(const struct dotlock_settings *set, const char *path,
+		      enum dotlock_create_flags flags,
+		      struct dotlock **dotlock_r);
+/* Replaces the file dotlock protects with the dotlock file itself. */
+int file_dotlock_replace(struct dotlock **dotlock,
+			 enum dotlock_replace_flags flags);
 
 #endif



More information about the dovecot-cvs mailing list