file-dotlock.c revision 181aa01111e2de2dae413b4c1ccfcfc4e801ac40
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "lib.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "str.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "hex-binary.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "hostpid.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "randgen.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "write-full.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "file-dotlock.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include <stdio.h>
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include <stdlib.h>
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include <signal.h>
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include <time.h>
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include <sys/stat.h>
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen/* 0.1 .. 0.2msec */
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainenstruct lock_info {
657afb33796f8216c568ad813627da89970760beTimo Sirainen const char *path, *lock_path, *temp_path;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen unsigned int stale_timeout;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen unsigned int immediate_stale_timeout;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen int fd;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen dev_t dev;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ino_t ino;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen off_t size;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen time_t ctime, mtime;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainen off_t last_size;
657afb33796f8216c568ad813627da89970760beTimo Sirainen time_t last_ctime, last_mtime;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen time_t last_change;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen pid_t pid;
657afb33796f8216c568ad813627da89970760beTimo Sirainen time_t last_pid_check;
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen};
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainen
4ac5448461b63de9637de839fbc611a3d503287cTimo Sirainenstatic pid_t read_local_pid(const char *lock_path)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen{
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen char buf[512], *host;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen int fd;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen ssize_t ret;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
d368b5e0c6ecc4361de943119db898e9c62e5f2cTimo Sirainen fd = open(lock_path, O_RDONLY);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen if (fd == -1)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen return -1; /* ignore the actual error */
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen /* read line */
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen ret = read(fd, buf, sizeof(buf)-1);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen (void)close(fd);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen if (ret <= 0)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen return -1;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen /* fix the string */
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen if (buf[ret-1] == '\n')
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen ret--;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen buf[ret] = '\0';
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen /* it should contain pid:host */
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen host = strchr(buf, ':');
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (host == NULL)
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen return -1;
657afb33796f8216c568ad813627da89970760beTimo Sirainen *host++ = '\0';
657afb33796f8216c568ad813627da89970760beTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainen /* host must be ours */
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (strcmp(host, my_hostname) != 0)
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (!is_numeric(buf, '\0'))
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return (pid_t)strtoul(buf, NULL, 0);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen}
657afb33796f8216c568ad813627da89970760beTimo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainenstatic int check_lock(time_t now, struct lock_info *lock_info)
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen{
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen struct stat st;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (lstat(lock_info->lock_path, &st) < 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (errno != ENOENT) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("lstat(%s) failed: %m", lock_info->lock_path);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return 1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (lock_info->immediate_stale_timeout != 0 &&
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen now > st.st_mtime + (time_t)lock_info->immediate_stale_timeout &&
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen now > st.st_ctime + (time_t)lock_info->immediate_stale_timeout) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen /* old lock file */
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->lock_path);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen }
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen return 1;
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen }
826cb2b19f57bb9b6f73018b585bd922e820f9f6Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (lock_info->stale_timeout == 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen /* no change checking */
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return 0;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (lock_info->ino != st.st_ino ||
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen !CMP_DEV_T(lock_info->dev, st.st_dev) ||
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen lock_info->ctime != st.st_ctime ||
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen lock_info->mtime != st.st_mtime ||
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->size != st.st_size) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen /* either our first check or someone else got the lock file.
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen check if it contains a pid whose existence we can verify */
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->dev = st.st_dev;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->ino = st.st_ino;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->ctime = st.st_ctime;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->mtime = st.st_mtime;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->size = st.st_size;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->pid = read_local_pid(lock_info->lock_path);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen lock_info->last_change = now;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (lock_info->pid != -1) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen /* we've local PID. Check if it exists. */
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (lock_info->last_pid_check == now)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return 0;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (kill(lock_info->pid, 0) == 0 || errno != ESRCH)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return 0;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen /* doesn't exist - go ahead and delete */
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->lock_path);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return -1;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return 1;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen if (lock_info->last_change != now) {
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen if (stat(lock_info->path, &st) < 0) {
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if (errno == ENOENT) {
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen /* file doesn't exist. treat it as if
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen it hasn't changed */
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen } else {
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen i_error("stat(%s) failed: %m", lock_info->path);
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen return -1;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen }
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen } else if (lock_info->last_size != st.st_size ||
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen lock_info->last_ctime != st.st_ctime ||
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen lock_info->last_mtime != st.st_mtime) {
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen lock_info->last_change = now;
78ed6a99e980228a75fa59cff84327dc0ea82857Timo Sirainen lock_info->last_size = st.st_size;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen lock_info->last_ctime = st.st_ctime;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen lock_info->last_mtime = st.st_mtime;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (now > lock_info->last_change + (time_t)lock_info->stale_timeout) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen /* no changes for a while, assume stale lock */
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->lock_path);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return -1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return 1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return 0;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen}
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainenstatic int create_temp_file(const char *prefix, const char **path_r)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen{
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen string_t *path;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen size_t len;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen struct stat st;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen char randbuf[8];
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen int fd;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen path = t_str_new(256);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str_append(path, prefix);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen len = str_len(path);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
3c9fbc33ee42feb08a6ac854ccbe833f538067f2Timo Sirainen for (;;) {
3c9fbc33ee42feb08a6ac854ccbe833f538067f2Timo Sirainen do {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen random_fill(randbuf, sizeof(randbuf));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str_truncate(path, len);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str_append(path,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen binary_to_hex(randbuf, sizeof(randbuf)));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen *path_r = str_c(path);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen } while (stat(*path_r, &st) == 0);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (errno != ENOENT) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen i_error("stat(%s) failed: %m", *path_r);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return -1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen fd = open(*path_r, O_RDWR | O_EXCL | O_CREAT, 0666);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (fd != -1)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return fd;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (errno != EEXIST) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen i_error("open(%s) failed: %m", *path_r);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return -1;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen}
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainenstatic int try_create_lock(struct lock_info *lock_info, const char *temp_prefix)
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen{
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen const char *str, *p;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (lock_info->temp_path == NULL) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen /* we'll need our temp file first. */
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (temp_prefix == NULL) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen temp_prefix = t_strconcat(".temp.", my_hostname, ".",
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen my_pid, ".", NULL);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen p = *temp_prefix == '/' ? NULL :
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen strrchr(lock_info->lock_path, '/');
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (p != NULL) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen str = t_strdup_until(lock_info->lock_path, p+1);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen temp_prefix = t_strconcat(str, temp_prefix, NULL);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen lock_info->fd = create_temp_file(temp_prefix, &str);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (lock_info->fd == -1)
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen return -1;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen lock_info->temp_path = str;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (link(lock_info->temp_path, lock_info->lock_path) < 0) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (errno == EEXIST)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return 0;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen i_error("link(%s, %s) failed: %m",
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_info->temp_path, lock_info->lock_path);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return -1;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (unlink(lock_info->temp_path) < 0 && errno != ENOENT) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->temp_path);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* non-fatal, continue */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen lock_info->temp_path = NULL;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return 1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic int dotlock_create(const char *path, const char *temp_prefix,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen int checkonly, int *fd,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned int timeout, unsigned int stale_timeout,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned int immediate_stale_timeout,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen int (*callback)(unsigned int secs_left, int stale,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen void *context),
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen void *context)
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen{
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen const char *lock_path;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen struct lock_info lock_info;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen unsigned int stale_notify_threshold;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen unsigned int change_secs, wait_left;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen time_t now, max_wait_time, last_notify;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen int do_wait, ret;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen now = time(NULL);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_path = t_strconcat(path, ".lock", NULL);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen stale_notify_threshold = stale_timeout / 2;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen max_wait_time = now + timeout;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen memset(&lock_info, 0, sizeof(lock_info));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen lock_info.path = path;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen lock_info.lock_path = lock_path;
4f7720c29123044476d0c44996e38dffa91c36e6Timo Sirainen lock_info.stale_timeout = stale_timeout;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_info.immediate_stale_timeout = immediate_stale_timeout;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_info.last_change = now;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_info.fd = -1;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen last_notify = 0; do_wait = FALSE;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen do {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (do_wait) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen do_wait = FALSE;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen ret = check_lock(now, &lock_info);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (ret < 0)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen break;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (ret == 1) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (checkonly)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen break;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen ret = try_create_lock(&lock_info, temp_prefix);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (ret != 0)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen break;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen do_wait = TRUE;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen if (last_notify != now && callback != NULL) {
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen last_notify = now;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen change_secs = now - lock_info.last_change;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen wait_left = max_wait_time - now;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen t_push();
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (change_secs >= stale_notify_threshold &&
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen change_secs <= wait_left) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (!callback(stale_timeout - change_secs,
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen TRUE, context)) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* we don't want to override */
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen lock_info.last_change = now;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen } else {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen (void)callback(wait_left, FALSE, context);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen t_pop();
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen }
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen now = time(NULL);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen } while (now < max_wait_time);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (ret <= 0 && lock_info.fd != -1) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen int old_errno = errno;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen (void)close(lock_info.fd);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_info.fd = -1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen errno = old_errno;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen *fd = lock_info.fd;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen if (ret == 0)
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen errno = EAGAIN;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen return ret;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainenint file_lock_dotlock(const char *path, const char *temp_prefix, int checkonly,
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen unsigned int timeout, unsigned int stale_timeout,
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen unsigned int immediate_stale_timeout,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen int (*callback)(unsigned int secs_left, int stale,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen void *context),
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen void *context, struct dotlock *dotlock_r)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen{
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen const char *lock_path, *str;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen struct stat st;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen int fd, ret;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen lock_path = t_strconcat(path, ".lock", NULL);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen ret = dotlock_create(path, temp_prefix, checkonly, &fd,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen timeout, stale_timeout, immediate_stale_timeout,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen callback, context);
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (ret <= 0 || checkonly)
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen return ret;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen /* write our pid and host, if possible */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str = t_strdup_printf("%s:%s", my_pid, my_hostname);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (write_full(fd, str, strlen(str)) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* failed, leave it empty then */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (ftruncate(fd, 0) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("ftruncate(%s) failed: %m", lock_path);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen (void)close(fd);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return -1;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* save the inode info after writing */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (fstat(fd, &st) < 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("fstat(%s) failed: %m", lock_path);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen (void)close(fd);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (close(fd) < 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("fstat(%s) failed: %m", lock_path);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen dotlock_r->dev = st.st_dev;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen dotlock_r->ino = st.st_ino;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen dotlock_r->mtime = st.st_mtime;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return 1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic int dotlock_delete(const char *path, const struct dotlock *dotlock)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const char *lock_path;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct stat st;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen lock_path = t_strconcat(path, ".lock", NULL);
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (lstat(lock_path, &st) < 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (errno == ENOENT) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_warning("Our dotlock file %s was deleted", lock_path);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return 0;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("lstat(%s) failed: %m", lock_path);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen }
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen if (dotlock->ino != st.st_ino ||
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen !CMP_DEV_T(dotlock->dev, st.st_dev)) {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen i_warning("Our dotlock file %s was overridden", lock_path);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen return 0;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen }
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen if (dotlock->mtime != st.st_mtime) {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen i_warning("Our dotlock file %s was modified (%s vs %s), "
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen "assuming it wasn't overridden", lock_path,
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen dec2str(dotlock->mtime), dec2str(st.st_mtime));
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen }
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen if (unlink(lock_path) < 0) {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen if (errno == ENOENT) {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen i_warning("Our dotlock file %s was deleted", lock_path);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen return 0;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen }
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen i_error("unlink(%s) failed: %m", lock_path);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen return -1;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen }
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen return 1;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen}
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainenint file_unlock_dotlock(const char *path, const struct dotlock *dotlock)
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen{
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen return dotlock_delete(path, dotlock);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen}
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainenint file_dotlock_open(const char *path, const char *temp_prefix,
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen unsigned int timeout, unsigned int stale_timeout,
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen unsigned int immediate_stale_timeout,
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen int (*callback)(unsigned int secs_left, int stale,
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen void *context),
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen void *context)
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen{
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen int ret, fd;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen ret = dotlock_create(path, temp_prefix, FALSE, &fd,
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen timeout, stale_timeout, immediate_stale_timeout,
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen callback, context);
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen if (ret <= 0)
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen return -1;
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen return fd;
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen}
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainenint file_dotlock_replace(const char *path, int fd, int verify_owner)
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen{
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen struct stat st, st2;
f6ef1961e6d02c299b418e3c7038a8b664ffffc9Timo Sirainen const char *lock_path;
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen lock_path = t_strconcat(path, ".lock", NULL);
31e7be5e1d41a77f08d26cef46aba1df24b3f1baTimo Sirainen if (verify_owner) {
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (fstat(fd, &st) < 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("fstat(%s) failed: %m", lock_path);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen (void)close(fd);
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen return -1;
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen }
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen }
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen if (close(fd) < 0) {
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen i_error("close(%s) failed: %m", lock_path);
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (verify_owner) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (lstat(lock_path, &st2) < 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("lstat(%s) failed: %m", lock_path);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen if (st.st_ino != st2.st_ino ||
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen !CMP_DEV_T(st.st_dev, st2.st_dev)) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_warning("Our dotlock file %s was overridden",
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen lock_path);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return 0;
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (rename(lock_path, path) < 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("rename(%s, %s) failed: %m", lock_path, path);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e4d34f2fbee451219599d71505594df704093ce3Timo Sirainen return 1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen}
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainenint file_dotlock_delete(const char *path, int fd)
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen{
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen struct dotlock dotlock;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen struct stat st;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (fstat(fd, &st) < 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("fstat(%s) failed: %m",
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen t_strconcat(path, ".lock", NULL));
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen (void)close(fd);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen if (close(fd) < 0) {
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen i_error("close(%s) failed: %m",
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen t_strconcat(path, ".lock", NULL));
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return -1;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen }
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen dotlock.dev = st.st_dev;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen dotlock.ino = st.st_ino;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen dotlock.mtime = st.st_mtime;
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen return dotlock_delete(path, &dotlock);
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen}
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen