bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* 0.1 .. 0.2msec */
62461eb609e1d852e027cf4e07d30d51288678a2Aki Tuomi#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)i_rand() % 100000)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int (*func)(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
9d6dec796909384293006e4289436579089d88d5Timo Sirainenstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
9d6dec796909384293006e4289436579089d88d5Timo Sirainen { MBOX_LOCK_DOTLOCK_TRY, "dotlock_try", mbox_lock_dotlock_try },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainenmbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainenmbox_unlock_files(struct mbox_lock_context *ctx);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic void mbox_read_lock_methods(const char *str, const char *env,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen for (type = 0; lock_data[type].name != NULL; type++) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (strcasecmp(*lock, lock_data[type].name) == 0) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen for (i = 0; i < dest; i++) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen i_fatal("%s: Duplicated value %s", env, *lock);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen /* @UNSAFE */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void mbox_init_lock_settings(struct mbox_storage *storage)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox_read_lock_methods(storage->set->mbox_read_locks,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen mbox_read_lock_methods(storage->set->mbox_write_locks,
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* check that read/write list orders match. write_locks must contain
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen at least read_locks and possibly more. */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (read_locks[r] != (enum mbox_lock_type)-1) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen i_fatal("mbox read/write lock list settings are invalid. "
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen "Lock ordering must be the same with both, "
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen "and write locks must contain all read locks "
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen "(and possibly more)");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen storage->read_locks = p_new(storage->storage.pool,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen sizeof(*storage->read_locks) * (MBOX_LOCK_COUNT+1));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen storage->write_locks = p_new(storage->storage.pool,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen sizeof(*storage->write_locks) * (MBOX_LOCK_COUNT+1));
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (ctx->checked_file || lock_type == F_UNLCK)
08ea8b302b62bc688f6b34f89f674e08eda7828cTimo Sirainen /* we could flush NFS file handle cache here if we wanted to
08ea8b302b62bc688f6b34f89f674e08eda7828cTimo Sirainen be sure that the file is latest, but mbox files get rarely
08ea8b302b62bc688f6b34f89f674e08eda7828cTimo Sirainen deleted and the flushing might cause errors (e.g. EBUSY for
08ea8b302b62bc688f6b34f89f674e08eda7828cTimo Sirainen trying to flush a /var/mail mountpoint) */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (nfs_safe_stat(mailbox_get_path(&mbox->box), &st) < 0) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen /* get next index we wish to try locking. it's the one after
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen dotlocking. */
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen if (lock_types[i] != (enum mbox_lock_type)-1 &&
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen /* we couldn't get fd lock -
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen it's really locked */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen index_storage_lock_notify(&ctx->mbox->box, stale ?
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen /* shouldn't get here */
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainenstatic int ATTR_NULL(2) ATTR_NOWARN_UNUSED_RESULT
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenmbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box, "open(.) failed: %m");
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen /* allow dotlocks to be created only for files we can read while we're
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen unprivileged. to make sure there are no race conditions we first
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen have to chdir to the mbox file's directory and then use relative
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen paths. unless this is done, users could:
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen - create *.lock files to any directory writable by the
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen privileged group
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen - DoS other users by dotlocking their mailboxes infinitely
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen /* already relative */
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen /* we're now privileged - avoid doing as much as possible */
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen ret = file_dotlock_create(set, fname, 0, &mbox->mbox_dotlock);
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen eacces_error_get_creating("file_dotlock_create",
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box, "%s", errmsg);
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_create()");
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen /* we're now privileged - avoid doing as much as possible */
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen ret = file_dotlock_delete(&mbox->mbox_dotlock);
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_delete()");
0ff28df76775a0740faa4370ec72d5a6a97534bfTimo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_touch()");
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box, "fchdir() failed: %m");
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainenmbox_dotlock_log_eacces_error(struct mbox_mailbox *mbox, const char *path)
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen errmsg = eacces_error_get_creating("file_dotlock_create", path);
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen dir = dir == NULL ? "." : t_strdup_until(path, dir);
fbb324fedccfd1cff9fb41b64f715ca77e5d588fTimo Sirainen /* allow privileged locking for
fbb324fedccfd1cff9fb41b64f715ca77e5d588fTimo Sirainen a) user's own INBOX,
fbb324fedccfd1cff9fb41b64f715ca77e5d588fTimo Sirainen b) another user's shared INBOX, and
fbb324fedccfd1cff9fb41b64f715ca77e5d588fTimo Sirainen c) anything called INBOX (in inbox=no namespace) */
fbb324fedccfd1cff9fb41b64f715ca77e5d588fTimo Sirainen if (!mbox->box.inbox_any && strcmp(mbox->box.name, "INBOX") != 0) {
6fbd30cc189c5acb4cfce841e17ed0eeff5056f4Timo Sirainen "%s (not INBOX -> no privileged locking)", errmsg);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen dir = mailbox_list_get_root_forced(mbox->box.list,
dcf49e7ccf042982fde41ce256723f925fb9f1e4Timo Sirainen "%s (under root dir %s -> no privileged locking)",
dcf49e7ccf042982fde41ce256723f925fb9f1e4Timo Sirainen (st.st_mode & 02) == 0 && /* not world-writable */
dcf49e7ccf042982fde41ce256723f925fb9f1e4Timo Sirainen (st.st_mode & 020) != 0) { /* group-writable */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen "%s (set mail_privileged_group=%s)", errmsg, name);
dcf49e7ccf042982fde41ce256723f925fb9f1e4Timo Sirainen "%s (nonstandard permissions in %s)", errmsg, dir);
9d6dec796909384293006e4289436579089d88d5Timo Sirainenmbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen "file_dotlock_delete()");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen set.use_excl_lock = mbox->storage->storage.set->dotlock_use_excl;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen set.nfs_flush = mbox->storage->storage.set->mail_nfs_storage;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen set.timeout = mail_storage_get_lock_timeout(&mbox->storage->storage,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen set.stale_timeout = mbox->storage->set->mbox_dotlock_change_timeout;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen ret = file_dotlock_create(&set, mailbox_get_path(&mbox->box), 0,
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen /* success / timeout */
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen } else if (errno == EACCES && restrict_access_have_priv_gid() &&
7f97ca94363c9e38fbbaaef204d6d01c54af6fc4Timo Sirainen /* try again, this time with extra privileges */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen mbox_dotlock_log_eacces_error(mbox, mailbox_get_path(&mbox->box));
62ccd8152d2f0142ab3301da4f5270b9d4f06718Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_create()");
9d6dec796909384293006e4289436579089d88d5Timo Sirainen if ((ENOSPACE(errno) || errno == EACCES) && try)
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_error(&mbox->storage->storage,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
9d6dec796909384293006e4289436579089d88d5Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
9d6dec796909384293006e4289436579089d88d5Timo Sirainen return mbox_lock_dotlock_int(ctx, lock_type, FALSE);
9d6dec796909384293006e4289436579089d88d5Timo Sirainenstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
9d6dec796909384293006e4289436579089d88d5Timo Sirainen return mbox_lock_dotlock_int(ctx, lock_type, TRUE);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen /* usually we're waiting here, but if we came from
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen mbox_lock_dotlock(), we just want to try locking */
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen while (flock(ctx->mbox->mbox_fd, lock_type) < 0) {
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen if (errno == EWOULDBLOCK && max_wait_time == 0) {
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen /* non-blocking lock trying failed */
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen /* notify locks once every 5 seconds.
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen try to use rounded values. */
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen else if (max_wait_time == 0) {
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen /* usually we're waiting here, but if we came from
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen mbox_lock_dotlock(), we just want to try locking */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen /* non-blocking lock trying failed */
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen /* notify locks once every 5 seconds.
35077ff71c0082c1370d9c296abce3153f645958Timo Sirainen try to use rounded values. */
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
7c27b0ab7213121ea43994499c04059413f6d0f2Timo Sirainen /* usually we're waiting here, but if we came from
7c27b0ab7213121ea43994499c04059413f6d0f2Timo Sirainen mbox_lock_dotlock(), we just want to try locking */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen while (fcntl(ctx->mbox->mbox_fd, wait_type, &fl) < 0) {
88de8e8fb4ad86f59ac0c4d85f5a9103dfd3fcc0Timo Sirainen /* non-blocking lock trying failed */
6797b2bb35596ec47d7f140eba79d4c686f370bcTimo Sirainen "fcntl() failed with mbox file %s: "
6797b2bb35596ec47d7f140eba79d4c686f370bcTimo Sirainen "File is locked by another process (EACCES)",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* notify locks once every 5 seconds.
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen try to use rounded values. */
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainenmbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
8e047750fa23706e883b14584d0ed7c4bfde3892Timo Sirainen if (ctx->locked_status[type] == locked_status)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ret = lock_data[type].func(ctx, lock_type, max_wait_time);
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainenstatic int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!mbox->storage->lock_settings_initialized)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* read-only mbox stream. no need to lock. */
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen mail_storage_get_lock_timeout(&mbox->storage->storage,
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping to shared lock. first drop those that we
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen don't remove completely. */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; i < MBOX_LOCK_COUNT; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_error(&mbox->storage->storage,
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping to shared lock: drop the locks that are only
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen in write list */
8e047750fa23706e883b14584d0ed7c4bfde3892Timo Sirainen memset(ctx.locked_status, 0, sizeof(ctx.locked_status));
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint mbox_lock(struct mbox_mailbox *mbox, int lock_type,
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen unsigned int *lock_id_r)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const char *path = mailbox_get_path(&mbox->box);
4780c036a0f52079068bd23e8a77b67ff457dba6Timo Sirainen if (lock_type == F_RDLCK && mbox->external_transactions > 0 &&
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen /* we have a transaction open that is going to save mails
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen and apparently also wants to read from the same mailbox
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen (copy, move, catenate). we need to write lock the mailbox,
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainen since we can't later upgrade a read lock to write lock. */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* allow only unlock -> shared/exclusive or exclusive -> shared */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(lock_type == F_RDLCK || mbox->mbox_lock_type != F_RDLCK);
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen ret = mbox_update_locking(mbox, lock_type, &fcntl_locked);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (mbox->storage->storage.set->mail_nfs_storage) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen nfs_flush_attr_cache_fd_locked(path, mbox_fd);
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen istream_raw_mbox_set_locked(mbox->mbox_stream);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_unlock_files(struct mbox_lock_context *ctx)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(mbox->mbox_lock_id == (lock_id & ~1));
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping exclusive lock */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* drop to shared lock */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping shared lock */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* all locks gone */
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen /* make sure we don't read the stream while unlocked */
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen istream_raw_mbox_set_unlocked(mbox->mbox_stream);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen for (i = 0; i < MBOX_LOCK_COUNT; i++)
86c6b2546b0bbfce326583f14d05f59674a6d861Timo Sirainenunsigned int mbox_get_cur_lock_id(struct mbox_mailbox *mbox)