bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include "lib.h"
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include "ioloop.h"
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include "str.h"
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include "read-full.h"
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include "write-full.h"
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen#include "eacces-error.h"
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen#include "mailbox-list.h"
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include "mailbox-uidvalidity.h"
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include <stdio.h>
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include <unistd.h>
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include <dirent.h>
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#include <fcntl.h>
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen#include <sys/stat.h>
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen#define RETRY_COUNT 10
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainenstatic uint32_t mailbox_uidvalidity_next_fallback(void)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen{
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen static uint32_t uid_validity = 0;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* we failed to use the uidvalidity file. don't fail the mailbox
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen creation because of it though, most of the time it's safe enough
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen to use the current time as the uidvalidity value. */
0e881a691e6d2d2836d923ef3e92b14aeda60f0dTimo Sirainen if (uid_validity < (uint32_t)ioloop_time)
0e881a691e6d2d2836d923ef3e92b14aeda60f0dTimo Sirainen uid_validity = (uint32_t)ioloop_time;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen else
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen uid_validity++;
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen if (uid_validity == 0)
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen uid_validity = 1;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return uid_validity;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen}
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenstatic void mailbox_uidvalidity_write(struct mailbox_list *list,
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen const char *path, uint32_t uid_validity)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen{
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen char buf[8+1];
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen int fd;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen struct mailbox_permissions perm;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mode_t old_mask;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mailbox_list_get_root_permissions(list, &perm);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen old_mask = umask(0666 & ~perm.file_create_mode);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen fd = open(path, O_RDWR | O_CREAT, 0666);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen umask(old_mask);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (fd == -1) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("open(%s) failed: %m", path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen if (perm.file_create_gid != (gid_t)-1 &&
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) {
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen if (errno == EPERM) {
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen i_error("%s", eperm_error_get_chgrp("fchown", path,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen perm.file_create_gid,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen perm.file_create_gid_origin));
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen } else {
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen i_error("fchown(%s, -1, %ld) failed: %m",
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen path, (long)perm.file_create_gid);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen }
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen }
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_snprintf(buf, sizeof(buf), "%08x", uid_validity) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (pwrite_full(fd, buf, strlen(buf), 0) < 0)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("write(%s) failed: %m", path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (close(fd) < 0)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("close(%s) failed: %m", path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen}
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainenstatic int
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainenmailbox_uidvalidity_rename(const char *path, uint32_t *uid_validity,
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen bool log_enoent)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen{
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen string_t *src, *dest;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t prefix_len;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen int ret;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen src = t_str_new(256);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen str_append(src, path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen dest = t_str_new(256);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen str_append(dest, path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen prefix_len = str_len(src);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen for (i = 0; i < RETRY_COUNT; i++) {
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen str_truncate(src, prefix_len);
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen str_truncate(dest, prefix_len);
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen str_printfa(src, ".%08x", *uid_validity);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen *uid_validity += 1;
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen if (*uid_validity == 0)
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen *uid_validity += 1;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen str_printfa(dest, ".%08x", *uid_validity);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if ((ret = rename(str_c(src), str_c(dest))) == 0 ||
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen errno != ENOENT)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen break;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* possibly a race condition. try the next value. */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen if (ret < 0 && (errno != ENOENT || log_enoent))
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("rename(%s, %s) failed: %m", str_c(src), str_c(dest));
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return ret;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen}
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenstatic uint32_t
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenmailbox_uidvalidity_next_rescan(struct mailbox_list *list, const char *path)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen{
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen DIR *d;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen struct dirent *dp;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen const char *fname, *dir, *prefix, *tmp;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t prefix_len;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen uint32_t cur_value, min_value, max_value;
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen mode_t old_mask;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen int fd;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen fname = strrchr(path, '/');
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (fname == NULL) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen dir = ".";
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen fname = path;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen } else {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen dir = t_strdup_until(path, fname);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen fname++;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen d = opendir(dir);
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen if (d == NULL && errno == ENOENT) {
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen /* FIXME: the PATH_TYPE_CONTROL should come as a parameter, but
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen that's an API change, do it in v2.3. it's not really a
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen problem though, since currently all backends use control
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen dirs for the uidvalidity file. */
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen (void)mailbox_list_mkdir_root(list, dir, MAILBOX_LIST_PATH_TYPE_CONTROL);
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen d = opendir(dir);
8cadc80b21c1087b6dd1b48a6522dcc52a081eacTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (d == NULL) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("opendir(%s) failed: %m", dir);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return mailbox_uidvalidity_next_fallback();
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen prefix = t_strconcat(fname, ".", NULL);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen prefix_len = strlen(prefix);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* just in case there happens to be multiple matching uidvalidity
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen files, track the min/max values. use the max value and delete the
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen min value file. */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen max_value = 0; min_value = (uint32_t)-1;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen while ((dp = readdir(d)) != NULL) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (strncmp(dp->d_name, prefix, prefix_len) == 0) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_to_uint32_hex(dp->d_name + prefix_len, &cur_value) >= 0) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (min_value > cur_value)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen min_value = cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (max_value < cur_value)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen max_value = cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (closedir(d) < 0)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("closedir(%s) failed: %m", dir);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (max_value == 0) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* no uidvalidity files. create one. */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen for (i = 0; i < RETRY_COUNT; i++) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen cur_value = mailbox_uidvalidity_next_fallback();
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen tmp = t_strdup_printf("%s.%08x", path, cur_value);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen /* the file is empty, don't bother with permissions */
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen old_mask = umask(0);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0444);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen umask(old_mask);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (fd != -1 || errno != EEXIST)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen break;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* already exists. although it's quite unlikely we'll
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen hit this race condition. more likely we'll create
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen a duplicate file.. */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (fd == -1) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("creat(%s) failed: %m", tmp);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen mailbox_uidvalidity_write(list, path, cur_value);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (min_value != max_value) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* duplicate uidvalidity files, delete the oldest */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen tmp = t_strdup_printf("%s.%08x", path, min_value);
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink_if_exists(tmp);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen cur_value = max_value;
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen if (mailbox_uidvalidity_rename(path, &cur_value, TRUE) < 0)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return mailbox_uidvalidity_next_fallback();
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen mailbox_uidvalidity_write(list, path, cur_value);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen}
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenuint32_t mailbox_uidvalidity_next(struct mailbox_list *list, const char *path)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen{
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch char buf[8+1];
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen uint32_t cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen int fd, ret;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen fd = open(path, O_RDWR);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (fd == -1) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (errno != ENOENT)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("open(%s) failed: %m", path);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen ret = read_full(fd, buf, sizeof(buf)-1);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (ret < 0) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("read(%s) failed: %m", path);
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen buf[sizeof(buf)-1] = 0;
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen if (ret == 0 || str_to_uint32_hex(buf, &cur_value) < 0 ||
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen cur_value == 0) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* broken value */
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* we now have the current uidvalidity value that's hopefully correct */
5e93930ec684cac19d71c44e5e42690acf452a74Timo Sirainen if (mailbox_uidvalidity_rename(path, &cur_value, FALSE) < 0) {
af8b1248fed8529d26985460acdc4b1e4b7de675Timo Sirainen i_close_fd(&fd);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
af8b1248fed8529d26985460acdc4b1e4b7de675Timo Sirainen }
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* fast path succeeded. write the current value to the main
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen uidvalidity file. */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_snprintf(buf, sizeof(buf), "%08x", cur_value) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (pwrite_full(fd, buf, strlen(buf), 0) < 0)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("write(%s) failed: %m", path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if (close(fd) < 0)
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("close(%s) failed: %m", path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen return cur_value;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen}