file-dotlock.c revision fdcb22a688c4676face8db865736b217d9c07d19
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hex-binary.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hostpid.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "randgen.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "write-full.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "safe-mkstemp.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-dotlock.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdio.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <stdlib.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <signal.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <time.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <utime.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#include <sys/stat.h>
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#define DEFAULT_LOCK_SUFFIX ".lock"
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen/* 0.1 .. 0.2msec */
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen/* If the dotlock is newer than this, don't verify that the PID it contains
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen is valid (since it most likely is). */
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#define STALE_PID_CHECK_SECS 2
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen/* Maximum difference between current time and create file's ctime before
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen logging a warning. Should be less than a second in normal operation. */
f16c114c20bbd7d292d93415d1e56c8dd6abd3e7Timo Sirainen#define MAX_TIME_DIFF 30
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct dotlock {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dotlock_settings settings;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dev_t dev;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen ino_t ino;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen time_t mtime;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *lock_path;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen int fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen time_t lock_time;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen};
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainenstruct file_change_info {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dev_t dev;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ino_t ino;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen off_t size;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen time_t ctime, mtime;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen};
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenstruct lock_info {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen const struct dotlock_settings *set;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen const char *path, *lock_path, *temp_path;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen int fd;
f7d43647acc6dc80064c8c4cacf5bf86f754c530Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen struct file_change_info lock_info;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen struct file_change_info file_info;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen bool have_pid, use_io_notify;
98c1cf256927e254f0c092acd2ddcd7ea50bd009Timo Sirainen time_t last_pid_check;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen time_t last_change;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen};
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainenstatic struct dotlock *
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainenfile_dotlock_alloc(const struct dotlock_settings *settings)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen{
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen struct dotlock *dotlock;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen dotlock = i_new(struct dotlock, 1);
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen dotlock->settings = *settings;
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen if (dotlock->settings.lock_suffix == NULL)
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen dotlock->settings.lock_suffix = DEFAULT_LOCK_SUFFIX;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen dotlock->fd = -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return dotlock;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenstatic pid_t read_local_pid(const char *lock_path)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen char buf[512], *host;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen int fd;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen ssize_t ret;
445f9e31c6c3aa6c0a72be8565da8f6e594d24fbTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen fd = open(lock_path, O_RDONLY);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (fd == -1)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1; /* ignore the actual error */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* read line */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ret = read(fd, buf, sizeof(buf)-1);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen (void)close(fd);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (ret <= 0)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* fix the string */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (buf[ret-1] == '\n')
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen ret--;
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen buf[ret] = '\0';
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
178511b57faa7c3f8203dd8b7e4059d00cbfc23aTimo Sirainen /* it should contain pid:host */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen host = strchr(buf, ':');
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (host == NULL)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen *host++ = '\0';
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* host must be ours */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (strcmp(host, my_hostname) != 0)
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen return -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (!is_numeric(buf, '\0'))
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return (pid_t)strtoul(buf, NULL, 0);
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen}
9e59a1f3f095b3099478562cf3f3970a24736970Timo Sirainen
96c253a039f102fa78a313ee05200ab3970112dcTimo Sirainenstatic bool
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainenupdate_change_info(const struct stat *st, struct file_change_info *change,
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen time_t *last_change_r, time_t now)
c3412ddeb9abc13f99d3caf50faf76cd99f7e9d2Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (change->ino != st->st_ino || !CMP_DEV_T(change->dev, st->st_dev) ||
268fe0fe3e748ae313e08b0918aa114815cf9d7cTimo Sirainen change->ctime != st->st_ctime || change->mtime != st->st_mtime ||
268fe0fe3e748ae313e08b0918aa114815cf9d7cTimo Sirainen change->size != st->st_size) {
268fe0fe3e748ae313e08b0918aa114815cf9d7cTimo Sirainen time_t change_time = now;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (change->ctime == 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* First check, set last_change to file's change time.
02b79f9c2636da1829eee5b92753602bba8b67edTimo Sirainen Use mtime instead if it's higher, but only if it's
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen not higher than current time, because the mtime
b9ac6179d3aee0d1641a4ee1d78da28628929c61Timo Sirainen can also be used for keeping metadata. */
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen change_time = st->st_mtime > now ? st->st_ctime :
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen I_MAX(st->st_ctime, st->st_mtime);
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen if (*last_change_r < change_time)
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen *last_change_r = change_time;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen change->ino = st->st_ino;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen change->dev = st->st_dev;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen change->ctime = st->st_ctime;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen change->mtime = st->st_mtime;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen change->size = st->st_size;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen return TRUE;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return FALSE;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen}
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainenstatic int update_lock_info(time_t now, struct lock_info *lock_info,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen bool *changed_r)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen{
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen struct stat st;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen if (lstat(lock_info->lock_path, &st) < 0) {
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen if (errno != ENOENT) {
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen i_error("lstat(%s) failed: %m", lock_info->lock_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen *changed_r = update_change_info(&st, &lock_info->lock_info,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen &lock_info->last_change, now);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int check_lock(time_t now, struct lock_info *lock_info)
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen{
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen time_t stale_timeout = lock_info->set->stale_timeout;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen pid_t pid;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen bool changed;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen int ret;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if ((ret = update_lock_info(now, lock_info, &changed)) != 0)
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen return ret;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (changed) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* either our first check or someone else got the lock file.
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if the dotlock was created only a couple of seconds ago,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen don't bother to read its PID. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen pid = lock_info->lock_info.mtime >=
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen now - STALE_PID_CHECK_SECS ? -1 :
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen read_local_pid(lock_info->lock_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_info->have_pid = pid != -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else if (!lock_info->have_pid) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* no pid checking */
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen pid = -1;
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (lock_info->last_pid_check == now) {
36e2fa21c22452470c1509cc63de20f7415c7b5eTimo Sirainen /* we just checked the pid */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* re-read the pid. even if all times and inodes are the same,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen the PID in the file might have changed if lock files were
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen rapidly being recreated. */
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen pid = read_local_pid(lock_info->lock_path);
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen lock_info->have_pid = pid != -1;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen }
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (lock_info->have_pid) {
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen /* we've local PID. Check if it exists. */
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen if (kill(pid, 0) == 0 || errno != ESRCH) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (pid != getpid())
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen /* it's us. either we're locking it again, or it's a
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen stale lock file with same pid than us. either way,
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen recreate it.. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* doesn't exist - now check again if the dotlock was just
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen deleted or replaced */
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen if ((ret = update_lock_info(now, lock_info, &changed)) != 0)
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen return ret;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (!changed) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen /* still there, go ahead and override it */
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen if (unlink(lock_info->lock_path) < 0 &&
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen errno != ENOENT) {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen i_error("unlink(%s) failed: %m",
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen lock_info->lock_path);
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen return -1;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (stale_timeout == 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* no change checking */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if (now > lock_info->last_change + stale_timeout) {
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen struct stat st;
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen /* possibly stale lock file. check also the timestamp of the
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen file we're protecting. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (stat(lock_info->path, &st) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (errno == ENOENT) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* file doesn't exist. treat it as if
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen it hasn't changed */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("stat(%s) failed: %m", lock_info->path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (void)update_change_info(&st, &lock_info->file_info,
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen &lock_info->last_change, now);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen if (now > lock_info->last_change + stale_timeout) {
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen /* no changes for a while, assume stale lock */
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen if (unlink(lock_info->lock_path) < 0 && errno != ENOENT) {
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->lock_path);
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen return -1;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
2ae575a66f2a302f047f6de062a70b75f8bebc7bTimo Sirainen return 1;
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen}
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen
484efa22e65c509f787dbbc892351146c726c257Timo Sirainenstatic int file_write_pid(int fd, const char *path)
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen{
9a06cabdfdf4d5e2f19a07e506c3c7d08a7e7038Timo Sirainen const char *str;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* write our pid and host, if possible */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str = t_strdup_printf("%s:%s", my_pid, my_hostname);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (write_full(fd, str, strlen(str)) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* failed, leave it empty then */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ftruncate(fd, 0) < 0) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen i_error("ftruncate(%s) failed: %m", path);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return -1;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen return 0;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen}
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainenstatic int try_create_lock_hardlink(struct lock_info *lock_info, bool write_pid,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen string_t *tmp_path)
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen{
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen const char *temp_prefix = lock_info->set->temp_prefix;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen const char *p;
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (lock_info->temp_path == NULL) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* we'll need our temp file first. */
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen i_assert(lock_info->fd == -1);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen p = strrchr(lock_info->lock_path, '/');
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen str_truncate(tmp_path, 0);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (temp_prefix != NULL) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (*temp_prefix != '/' && p != NULL) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* add directory */
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen str_append_n(tmp_path, lock_info->lock_path,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen p - lock_info->lock_path);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen str_append_c(tmp_path, '/');
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
f0f9c8e94abac18f8acd91b9e724c4c32863723aTimo Sirainen str_append(tmp_path, temp_prefix);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen } else {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (p != NULL) {
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen /* add directory */
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen str_append_n(tmp_path, lock_info->lock_path,
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen p - lock_info->lock_path);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen str_append_c(tmp_path, '/');
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen str_printfa(tmp_path, ".temp.%s.%s.",
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen my_hostname, my_pid);
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen lock_info->fd = safe_mkstemp(tmp_path, 0666,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (uid_t)-1, (gid_t)-1);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (lock_info->fd == -1)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (write_pid) {
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen if (file_write_pid(lock_info->fd,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen str_c(tmp_path)) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen (void)close(lock_info->fd);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_info->fd = -1;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen return -1;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen lock_info->temp_path = str_c(tmp_path);
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen if (link(lock_info->temp_path, lock_info->lock_path) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (errno == EEXIST)
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen return 0;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("link(%s, %s) failed: %m",
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_info->temp_path, lock_info->lock_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
8af07808ba203f8709e2ff9eaf2291e1c4a4d53dTimo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (unlink(lock_info->temp_path) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("unlink(%s) failed: %m", lock_info->temp_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* non-fatal, continue */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_info->temp_path = NULL;
33d63688ed8b26dc333e3c2edbfb2fe6e412604dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
33d63688ed8b26dc333e3c2edbfb2fe6e412604dTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int try_create_lock_excl(struct lock_info *lock_info, bool write_pid)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int fd;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen fd = open(lock_info->lock_path, O_RDWR | O_EXCL | O_CREAT, 0666);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (fd == -1) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (errno == EEXIST)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return 0;
b9ac6179d3aee0d1641a4ee1d78da28628929c61Timo Sirainen
b9ac6179d3aee0d1641a4ee1d78da28628929c61Timo Sirainen i_error("open(%s) failed: %m", lock_info->lock_path);
b9ac6179d3aee0d1641a4ee1d78da28628929c61Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen if (write_pid) {
6e71799ee07bfd2289beae77c9bb5d7f1d30dccaTimo Sirainen if (file_write_pid(fd, lock_info->lock_path) < 0) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen (void)close(fd);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
7f3be7d885c75cdd77f536929a45bc9764595960Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_info->fd = fd;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainenstatic void dotlock_wait_end(struct ioloop *ioloop)
77af8c68c416179e717fc2d551f72ec50b499c13Timo Sirainen{
77af8c68c416179e717fc2d551f72ec50b499c13Timo Sirainen io_loop_stop(ioloop);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen}
77af8c68c416179e717fc2d551f72ec50b499c13Timo Sirainen
77af8c68c416179e717fc2d551f72ec50b499c13Timo Sirainenstatic void dotlock_wait(struct lock_info *lock_info)
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen{
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct ioloop *ioloop;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct io *io;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct timeout *to;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen if (!lock_info->use_io_notify) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return;
e5ee67f18b03015c88b579c8c1f17ebe6ce19b76Timo Sirainen }
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ioloop = io_loop_create();
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen switch (io_add_notify(lock_info->lock_path, dotlock_wait_end,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ioloop, &io)) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen case IO_NOTIFY_ADDED:
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen break;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen case IO_NOTIFY_NOTFOUND:
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen /* the lock file doesn't exist anymore, don't sleep */
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen io_loop_destroy(&ioloop);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen return;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen case IO_NOTIFY_DISABLED:
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* listening for files not supported */
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen io_loop_destroy(&ioloop);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen lock_info->use_io_notify = FALSE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen to = timeout_add(LOCK_RANDOM_USLEEP_TIME/1000,
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen dotlock_wait_end, ioloop);
88553367d677170a4b703b9d52aac9eabf91c656Timo Sirainen io_loop_run(ioloop);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen io_remove(&io);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen timeout_remove(&to);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen io_loop_destroy(&ioloop);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainenstatic int dotlock_create(const char *path, struct dotlock *dotlock,
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen enum dotlock_create_flags flags, bool write_pid)
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen{
3023fb352cbc2052b156f6d325c2629531a1b5b4Timo Sirainen const struct dotlock_settings *set = &dotlock->settings;
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen const char *lock_path;
e8a35266a5ceacdfafeeffd6bddae77931ff97ebTimo Sirainen struct lock_info lock_info;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen struct stat st;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen unsigned int stale_notify_threshold;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen unsigned int change_secs, wait_left;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen time_t now, max_wait_time, last_notify;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen string_t *tmp_path;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen bool do_wait;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen now = time(NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen lock_path = t_strconcat(path, set->lock_suffix, NULL);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen stale_notify_threshold = set->stale_timeout / 2;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen max_wait_time = (flags & DOTLOCK_CREATE_FLAG_NONBLOCK) != 0 ? 0 :
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen now + set->timeout;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen tmp_path = t_str_new(256);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen memset(&lock_info, 0, sizeof(lock_info));
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen lock_info.path = path;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen lock_info.set = set;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen lock_info.lock_path = lock_path;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen lock_info.fd = -1;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen lock_info.use_io_notify = set->use_io_notify;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen last_notify = 0; do_wait = FALSE;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen do {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (do_wait) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen dotlock_wait(&lock_info);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen do_wait = FALSE;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen }
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen ret = check_lock(now, &lock_info);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (ret < 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen break;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (ret == 1) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if ((flags & DOTLOCK_CREATE_FLAG_CHECKONLY) != 0)
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen break;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen ret = set->use_excl_lock ?
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen try_create_lock_excl(&lock_info, write_pid) :
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen try_create_lock_hardlink(&lock_info, write_pid,
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen tmp_path);
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (ret != 0)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen break;
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen do_wait = TRUE;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen if (last_notify != now && set->callback != NULL) {
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen last_notify = now;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen change_secs = now - lock_info.last_change;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen wait_left = max_wait_time - now;
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen
e68309fcfa2eaa88217fd51e7b4900fc9c20ef5dTimo Sirainen t_push();
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen if (change_secs >= stale_notify_threshold &&
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen change_secs <= wait_left) {
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen unsigned int secs_left =
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen set->stale_timeout < change_secs ?
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen 0 : set->stale_timeout - change_secs;
ab3c1eab9ca13916358a9e8b12df8212fefb7dbfTimo Sirainen if (!set->callback(secs_left, TRUE,
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen set->context)) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen /* we don't want to override */
3021a062b16ff0138408be6107d6bcd0ced280b9Timo Sirainen lock_info.last_change = now;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen } else {
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen (void)set->callback(wait_left, FALSE,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen set->context);
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen }
e5c08648676d1989f6e70b95e5990c26b3e8b96bTimo Sirainen t_pop();
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen now = time(NULL);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen } while (now < max_wait_time);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen if (ret > 0) {
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen if (fstat(lock_info.fd, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fstat(%s) failed: %m", lock_path);
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen ret = -1;
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen } else {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* successful dotlock creation */
4d25408732be27e91f0430f71e87242760c2517cTimo Sirainen dotlock->dev = st.st_dev;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->ino = st.st_ino;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->path = i_strdup(path);
1276e0340fe29495b6694dc7508f070cf6fca1cfTimo Sirainen dotlock->fd = lock_info.fd;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->lock_time = now;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_info.fd = -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (st.st_ctime + MAX_TIME_DIFF < now ||
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen st.st_ctime - MAX_TIME_DIFF > now) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_warning("Created dotlock file's timestamp is "
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "different than current time "
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen "(%s vs %s): %s", dec2str(st.st_ctime),
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dec2str(now), path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (lock_info.fd != -1) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int old_errno = errno;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (close(lock_info.fd) < 0)
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen i_error("close(%s) failed: %m", lock_path);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen errno = old_errno;
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (lock_info.temp_path != NULL) {
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen if (unlink(lock_info.temp_path) < 0)
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen i_error("unlink(%s) failed: %m", lock_info.temp_path);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret == 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen errno = EAGAIN;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return ret;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainenstatic void file_dotlock_free(struct dotlock *dotlock)
60d3fa9883237e896a8704275b6116fa46f7ffdaTimo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen int old_errno;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (dotlock->fd != -1) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen old_errno = errno;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (close(dotlock->fd) < 0)
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("close(%s) failed: %m", dotlock->path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->fd = -1;
064bfeee2f9156683b191cc0f3f7b242720942f7Timo Sirainen errno = old_errno;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen i_free(dotlock->path);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen i_free(dotlock->lock_path);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen i_free(dotlock);
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen}
7fd72a47d7ddfbd38c8697e228b6951f495dfb61Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainenint file_dotlock_create(const struct dotlock_settings *set, const char *path,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen enum dotlock_create_flags flags,
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen struct dotlock **dotlock_r)
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen{
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen struct dotlock *dotlock;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen const char *lock_path;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen struct stat st;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen int fd, ret;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen *dotlock_r = NULL;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen t_push();
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen dotlock = file_dotlock_alloc(set);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_path = t_strconcat(path, dotlock->settings.lock_suffix, NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen ret = dotlock_create(path, dotlock, flags, TRUE);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (ret <= 0 || (flags & DOTLOCK_CREATE_FLAG_CHECKONLY) != 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen file_dotlock_free(dotlock);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen t_pop();
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return ret;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen fd = dotlock->fd;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->fd = -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (close(fd) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("close(%s) failed: %m", lock_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen file_dotlock_free(dotlock);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen t_pop();
907723f35f4d3dfc774ca42d00a8a7b8ef90dd5dTimo Sirainen return -1;
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen }
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen
36816b5af1472ae76a1909ae3cf29fd614b2ebfcTimo Sirainen /* some NFS implementations may have used cached mtime in previous
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen fstat() call. Check again to avoid "dotlock was modified" errors. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (stat(lock_path, &st) < 0) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (errno != ENOENT)
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen i_error("stat(%s) failed: %m", lock_path);
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen else {
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen i_error("dotlock %s was immediately deleted under us",
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen lock_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen file_dotlock_free(dotlock);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen t_pop();
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen /* extra sanity check won't hurt.. */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (st.st_dev != dotlock->dev || st.st_ino != dotlock->ino) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("dotlock %s was immediately recreated under us",
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen lock_path);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen file_dotlock_free(dotlock);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen t_pop();
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen return -1;
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen dotlock->mtime = st.st_mtime;
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen
2cb565cd978aafd5714792b5161889986d49e431Timo Sirainen *dotlock_r = dotlock;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen t_pop();
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainenint file_dotlock_delete(struct dotlock **dotlock_p)
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen{
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen struct dotlock *dotlock;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen const char *lock_path;
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen struct stat st;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dc8552739fa29f011ab71ec383ec6d580a5a9661Timo Sirainen dotlock = *dotlock_p;
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen *dotlock_p = NULL;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen lock_path = file_dotlock_get_lock_path(dotlock);
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen if (lstat(lock_path, &st) < 0) {
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen if (errno == ENOENT) {
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen i_warning("Our dotlock file %s was deleted "
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen "(kept it %d secs)", lock_path,
8d5991f5c4a8840bf1ea754093dbec505564ab78Timo Sirainen (int)(time(NULL) - dotlock->lock_time));
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen file_dotlock_free(dotlock);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen return 0;
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen }
4214b59ac7f3899f8d887d055ef519f5a622d249Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen i_error("lstat(%s) failed: %m", lock_path);
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen file_dotlock_free(dotlock);
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen return -1;
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen }
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
930dcf1576f99057ad572420d9c75f3212e46a2eTimo Sirainen if (dotlock->ino != st.st_ino ||
c9a03c8a03a782488981f81bd7c6b5e01ff55f06Timo Sirainen !CMP_DEV_T(dotlock->dev, st.st_dev)) {
829c036d4ddfbd9ea49bd8a7c54e3057177d346eTimo Sirainen i_warning("Our dotlock file %s was overridden "
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen "(kept it %d secs)", lock_path,
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen (int)(dotlock->lock_time - time(NULL)));
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen errno = EEXIST;
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen file_dotlock_free(dotlock);
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (dotlock->mtime != st.st_mtime && dotlock->fd == -1) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_warning("Our dotlock file %s was modified (%s vs %s), "
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen "assuming it wasn't overridden (kept it %d secs)",
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen lock_path,
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen dec2str(dotlock->mtime), dec2str(st.st_mtime),
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen (int)(time(NULL) - dotlock->lock_time));
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen if (unlink(lock_path) < 0) {
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen if (errno == ENOENT) {
7a6b45405fb1544ac476e6eb1402a70cc1ddcdcfTimo Sirainen i_warning("Our dotlock file %s was deleted "
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen "(kept it %d secs)", lock_path,
b2ecd50bb98c44816cb07c17aa17fae2b425f941Timo Sirainen (int)(time(NULL) - dotlock->lock_time));
8907d617ce7c4f390c0f42f6f694db2fecdd5775Timo Sirainen file_dotlock_free(dotlock);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 0;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_error("unlink(%s) failed: %m", lock_path);
01cbf4ac5d44137ab434791be7f838d98d0fcf3bTimo Sirainen file_dotlock_free(dotlock);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return -1;
6a1e4eb2c6a267bec1e8704ce9137bebb7792702Timo Sirainen }
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainen
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen file_dotlock_free(dotlock);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return 1;
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen}
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenint file_dotlock_open(const struct dotlock_settings *set, const char *path,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen enum dotlock_create_flags flags,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct dotlock **dotlock_r)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen struct dotlock *dotlock;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int ret;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen dotlock = file_dotlock_alloc(set);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen t_push();
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen ret = dotlock_create(path, dotlock, flags, FALSE);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen t_pop();
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (ret <= 0) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen file_dotlock_free(dotlock);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen *dotlock_r = NULL;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
6a87059fc7d4e919aa55d0b208ff20708e13e2d7Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen *dotlock_r = dotlock;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return dotlock->fd;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenint file_dotlock_replace(struct dotlock **dotlock_p,
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen enum dotlock_replace_flags flags)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct dotlock *dotlock;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen struct stat st, st2;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen const char *lock_path;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen int fd;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen dotlock = *dotlock_p;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen *dotlock_p = NULL;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen fd = dotlock->fd;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if ((flags & DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) != 0)
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen dotlock->fd = -1;
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen lock_path = file_dotlock_get_lock_path(dotlock);
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if ((flags & DOTLOCK_REPLACE_FLAG_VERIFY_OWNER) != 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen if (fstat(fd, &st) < 0) {
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen i_error("fstat(%s) failed: %m", lock_path);
319944c0f35b311c998854e96d6463a084fd90aeTimo Sirainen file_dotlock_free(dotlock);
a393d9d6dabdc46cf724f8cb004a652b4036d53dTimo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (lstat(lock_path, &st2) < 0) {
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen i_error("lstat(%s) failed: %m", lock_path);
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen file_dotlock_free(dotlock);
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen return -1;
cece2b9cd692c06025cc0a7a0ff54d996a8c90efTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen if (st.st_ino != st2.st_ino ||
db7c9201c88e3d9bee10485194ee5b0c67249916Timo Sirainen !CMP_DEV_T(st.st_dev, st2.st_dev)) {
755fe6da51ab7f54aa1d86913cb344bffef60e79Timo Sirainen i_warning("Our dotlock file %s was overridden "
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "(kept it %d secs)", lock_path,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (int)(time(NULL) - dotlock->lock_time));
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen errno = EEXIST;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen file_dotlock_free(dotlock);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 0;
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen if (rename(lock_path, dotlock->path) < 0) {
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen i_error("rename(%s, %s) failed: %m", lock_path, dotlock->path);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen file_dotlock_free(dotlock);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return -1;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen file_dotlock_free(dotlock);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return 1;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen}
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainenint file_dotlock_touch(struct dotlock *dotlock)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen{
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen time_t now = time(NULL);
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen struct utimbuf buf;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen const char *lock_path;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen int ret = 0;
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen if (dotlock->mtime == now)
b225c3c65f360d7b833f09f9b2fb3035ed5ea600Timo Sirainen return 0;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen dotlock->mtime = now;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen buf.actime = buf.modtime = now;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen t_push();
a10e5606a9e93f49cf13b3a35c8dc3f5d6ab5909Timo Sirainen lock_path = file_dotlock_get_lock_path(dotlock);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if (utime(lock_path, &buf) < 0) {
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen i_error("utime(%s) failed: %m", lock_path);
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen ret = -1;
0a6f8311541ae59381171620b77f82be58be562eTimo Sirainen }
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen t_pop();
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen return ret;
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen}
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainenconst char *file_dotlock_get_lock_path(struct dotlock *dotlock)
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen{
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen if (dotlock->lock_path == NULL) {
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->lock_path =
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen i_strconcat(dotlock->path,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen dotlock->settings.lock_suffix, NULL);
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen }
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen return dotlock->lock_path;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen}
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen