bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainenstatic uint32_t mailbox_uidvalidity_next_fallback(void)
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. */
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenstatic void mailbox_uidvalidity_write(struct mailbox_list *list,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mailbox_list_get_root_permissions(list, &perm);
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen old_mask = umask(0666 & ~perm.file_create_mode);
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) {
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen i_error("%s", eperm_error_get_chgrp("fchown", path,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_snprintf(buf, sizeof(buf), "%08x", uid_validity) < 0)
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainenmailbox_uidvalidity_rename(const char *path, uint32_t *uid_validity,
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen for (i = 0; i < RETRY_COUNT; i++) {
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen if ((ret = rename(str_c(src), str_c(dest))) == 0 ||
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* possibly a race condition. try the next value. */
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen if (ret < 0 && (errno != ENOENT || log_enoent))
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen i_error("rename(%s, %s) failed: %m", str_c(src), str_c(dest));
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenmailbox_uidvalidity_next_rescan(struct mailbox_list *list, const char *path)
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i;
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);
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 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 /* 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 fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0444);
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.. */
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen mailbox_uidvalidity_write(list, path, cur_value);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* duplicate uidvalidity files, delete the oldest */
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen tmp = t_strdup_printf("%s.%08x", path, min_value);
3426a5f4c7925cfb76208c7b1abf49b861d273e3Timo Sirainen if (mailbox_uidvalidity_rename(path, &cur_value, TRUE) < 0)
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen mailbox_uidvalidity_write(list, path, cur_value);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainenuint32_t mailbox_uidvalidity_next(struct mailbox_list *list, const char *path)
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
08d8de8e25e2a130563911fea8378ab24bf8fc9dTimo Sirainen if (ret == 0 || str_to_uint32_hex(buf, &cur_value) < 0 ||
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* broken value */
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
300baf826ba39003b861e7716c35bae372e6f23eTimo Sirainen /* we now have the current uidvalidity value that's hopefully correct */
5e93930ec684cac19d71c44e5e42690acf452a74Timo Sirainen if (mailbox_uidvalidity_rename(path, &cur_value, FALSE) < 0) {
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next_rescan(list, path);
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)