bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen/*
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen Version 1 format has been used for most versions of Dovecot up to v1.0.x.
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen It's also compatible with Courier IMAP's courierimapuiddb file.
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen The format is:
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen header: 1 <uid validity> <next uid>
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen entry: <uid> <filename>
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen --
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen Version 2 format was written by a few development Dovecot versions, but
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen v1.0.x still parses the format. The format has <flags> field after <uid>.
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen --
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen Version 3 format is an extensible format used by Dovecot v1.1 and later.
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen It's also parsed by v1.0.2 (and later). The format is:
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen header: 3 [<key><value> ...]
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen entry: <uid> [<key><value> ...] :<filename>
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen See enum maildir_uidlist_*_ext_key for used keys.
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen*/
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hash.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-dotlock.h"
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include "nfs-workarounds.h"
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen#include "eacces-error.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-storage.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "maildir-filename.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-uidlist.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdio.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen/* NFS: How many times to retry reading dovecot-uidlist file if ESTALE
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen error occurs in the middle of reading it */
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#define UIDLIST_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen#define UIDLIST_VERSION 3
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen#define UIDLIST_COMPRESS_PERCENTAGE 75
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define UIDLIST_IS_LOCKED(uidlist) \
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ((uidlist)->lock_count > 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct maildir_uidlist_rec {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *filename;
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen unsigned char *extensions; /* <data>\0[<data>\0 ...]\0 */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo SirainenARRAY_DEFINE_TYPE(maildir_uidlist_rec_p, struct maildir_uidlist_rec *);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo SirainenHASH_TABLE_DEFINE_TYPE(path_to_maildir_uidlist_rec,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen char *, struct maildir_uidlist_rec *);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct maildir_uidlist {
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mailbox *box;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen char *path;
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct maildir_index_header *mhdr;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen int fd;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen dev_t fd_dev;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen ino_t fd_ino;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen off_t fd_size;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen unsigned int lock_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen struct dotlock_settings dotlock_settings;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen struct dotlock *dotlock;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen pool_t record_pool;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen ARRAY_TYPE(maildir_uidlist_rec_p) records;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE_TYPE(path_to_maildir_uidlist_rec) files;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen unsigned int change_counter;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int version;
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen unsigned int uid_validity, next_uid, prev_read_uid, last_seen_uid;
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen unsigned int hdr_next_uid;
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen unsigned int read_records_count, read_line_count;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uoff_t last_read_offset;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen string_t *hdr_extensions;
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_t mailbox_guid;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool recreate:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool recreate_on_change:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool initial_read:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool initial_hdr_read:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool retry_rewind:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool locked_refresh:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool unsorted:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool have_mailbox_guid:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool opened_readonly:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct maildir_uidlist_sync_ctx {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist *uidlist;
e32cf1b4430c4a5f28c9b5bb8b1366e7b06ed68dTimo Sirainen enum maildir_uidlist_sync_flags sync_flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen pool_t record_pool;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen ARRAY_TYPE(maildir_uidlist_rec_p) records;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE_TYPE(path_to_maildir_uidlist_rec) files;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen unsigned int first_unwritten_pos, first_new_pos;
38da5c23b0a8b4012e79fcf647a8749786c83c51Timo Sirainen unsigned int new_files_count;
bb592fc58fe5c3e81ad941637fbb30d1d1cd8694Timo Sirainen unsigned int finish_change_counter;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool partial:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool finished:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool changed:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool failed:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool locked:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct maildir_uidlist_iter_ctx {
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen struct maildir_uidlist *uidlist;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen struct maildir_uidlist_rec *const *next, *const *end;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen unsigned int change_counter;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen uint32_t prev_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainenstatic int maildir_uidlist_open_latest(struct maildir_uidlist *uidlist);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenstatic bool maildir_uidlist_iter_next_rec(struct maildir_uidlist_iter_ctx *ctx,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen struct maildir_uidlist_rec **rec_r);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainenstatic int maildir_uidlist_lock_timeout(struct maildir_uidlist *uidlist,
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen bool nonblock, bool refresh,
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen bool refresh_when_locked)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mailbox *box = uidlist->box;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const struct mailbox_permissions *perm = mailbox_get_permissions(box);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char *path = uidlist->path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mode_t old_mask;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen const enum dotlock_create_flags dotlock_flags =
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen nonblock ? DOTLOCK_CREATE_FLAG_NONBLOCK : 0;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen int i, ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (uidlist->lock_count > 0) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (!uidlist->locked_refresh && refresh_when_locked) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0)
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen return -1;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uidlist->lock_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
feaa6a3d82ea61496ced1f83a726ff33047c7da2Timo Sirainen index_storage_lock_notify_reset(box);
eb99fc24b7d1b2abb6b9217e2b732595069c908eTimo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen for (i = 0;; i++) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen old_mask = umask(0777 & ~perm->file_create_mode);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ret = file_dotlock_create(&uidlist->dotlock_settings, path,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen dotlock_flags, &uidlist->dotlock);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen umask(old_mask);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (ret > 0)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* failure */
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen if (ret == 0) {
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen mail_storage_set_error(box->storage,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
d67ac5f76cc02c227f4997878bb4aef48ee298faTimo Sirainen }
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen if (errno == EACCES) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "%s",
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen eacces_error_get_creating("file_dotlock_create", path));
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen } else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen "file_dotlock_create(%s) failed: %m",
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen path);
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* the control dir doesn't exist. create it unless the whole
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen mailbox was just deleted. */
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen if (!maildir_set_deleted(uidlist->box))
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen uidlist->lock_count++;
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen uidlist->locked_refresh = FALSE;
8a6fc472a12c5ec09e2bd19f1b3acd553d75ff91Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (refresh) {
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen /* make sure we have the latest changes before
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen changing anything */
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0) {
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen maildir_uidlist_unlock(uidlist);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return -1;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen }
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainenint maildir_uidlist_lock(struct maildir_uidlist *uidlist)
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen{
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen return maildir_uidlist_lock_timeout(uidlist, FALSE, TRUE, FALSE);
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen}
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainenint maildir_uidlist_try_lock(struct maildir_uidlist *uidlist)
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen{
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen return maildir_uidlist_lock_timeout(uidlist, TRUE, TRUE, FALSE);
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen}
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainenint maildir_uidlist_lock_touch(struct maildir_uidlist *uidlist)
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainen{
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainen i_assert(UIDLIST_IS_LOCKED(uidlist));
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainen
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainen return file_dotlock_touch(uidlist->dotlock);
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainen}
4673afe816ffbca769585e4518e9b3c3d72e95ddTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool maildir_uidlist_is_locked(struct maildir_uidlist *uidlist)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return UIDLIST_IS_LOCKED(uidlist);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
a0aedab7cd06125e4d73638b1bd0c01c7caa2626Timo Sirainenbool maildir_uidlist_is_read(struct maildir_uidlist *uidlist)
a0aedab7cd06125e4d73638b1bd0c01c7caa2626Timo Sirainen{
a0aedab7cd06125e4d73638b1bd0c01c7caa2626Timo Sirainen return uidlist->initial_read;
a0aedab7cd06125e4d73638b1bd0c01c7caa2626Timo Sirainen}
a0aedab7cd06125e4d73638b1bd0c01c7caa2626Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainenbool maildir_uidlist_is_open(struct maildir_uidlist *uidlist)
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen{
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen return uidlist->fd != -1;
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen}
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid maildir_uidlist_unlock(struct maildir_uidlist *uidlist)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_assert(uidlist->lock_count > 0);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (--uidlist->lock_count > 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen uidlist->locked_refresh = FALSE;
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen file_dotlock_delete(&uidlist->dotlock);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct mailbox *box = context;
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen index_storage_lock_notify(box, stale ?
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen secs_left);
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen return TRUE;
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen}
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstruct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mailbox *box = &mbox->box;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist *uidlist;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen const char *control_dir;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_CONTROL,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &control_dir) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen i_unreached();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uidlist = i_new(struct maildir_uidlist, 1);
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen uidlist->box = box;
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen uidlist->mhdr = &mbox->maildir_hdr;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen uidlist->fd = -1;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen uidlist->path = i_strconcat(control_dir, "/"MAILDIR_UIDLIST_NAME, NULL);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen i_array_init(&uidlist->records, 128);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&uidlist->files, default_pool, 4096,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen maildir_filename_base_hash,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen maildir_filename_base_cmp);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uidlist->next_uid = 1;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen uidlist->hdr_extensions = str_new(default_pool, 128);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fdcb22a688c4676face8db865736b217d9c07d19Timo Sirainen uidlist->dotlock_settings.use_io_notify = TRUE;
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen uidlist->dotlock_settings.use_excl_lock =
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen box->storage->set->dotlock_use_excl;
8da095519878426b012058e6f331a669f327f47fTimo Sirainen uidlist->dotlock_settings.nfs_flush =
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen box->storage->set->mail_nfs_storage;
2e7e4804d8a88b10e00a3f9ec3726759ae0a6a13Timo Sirainen uidlist->dotlock_settings.timeout =
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen mail_storage_get_lock_timeout(box->storage,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT + 2);
2e7e4804d8a88b10e00a3f9ec3726759ae0a6a13Timo Sirainen uidlist->dotlock_settings.stale_timeout =
2e7e4804d8a88b10e00a3f9ec3726759ae0a6a13Timo Sirainen MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT;
075086f56fdcc480b0e87aabde63128e30b49002Timo Sirainen uidlist->dotlock_settings.callback = dotlock_callback;
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen uidlist->dotlock_settings.context = box;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen uidlist->dotlock_settings.temp_prefix = mbox->storage->temp_prefix;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen return uidlist;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen}
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainenstatic void maildir_uidlist_close(struct maildir_uidlist *uidlist)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen if (uidlist->fd != -1) {
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen if (close(uidlist->fd) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen "close(%s) failed: %m", uidlist->path);
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen }
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen uidlist->fd = -1;
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen uidlist->fd_ino = 0;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->last_read_offset = 0;
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uidlist->read_line_count = 0;
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen}
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainenstatic void maildir_uidlist_reset(struct maildir_uidlist *uidlist)
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen{
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen maildir_uidlist_close(uidlist);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->last_seen_uid = 0;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->initial_hdr_read = FALSE;
950a4789af247d57874d99a09ed7a67be5ddc2dcTimo Sirainen uidlist->read_records_count = 0;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen hash_table_clear(uidlist->files, FALSE);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen array_clear(&uidlist->records);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen}
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainenvoid maildir_uidlist_deinit(struct maildir_uidlist **_uidlist)
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen{
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen struct maildir_uidlist *uidlist = *_uidlist;
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen i_assert(!UIDLIST_IS_LOCKED(uidlist));
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen *_uidlist = NULL;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)maildir_uidlist_update(uidlist);
85452efe6f9edd85e2ce45bfc4f198e9cb9b82bdTimo Sirainen maildir_uidlist_close(uidlist);
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&uidlist->files);
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&uidlist->record_pool);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen array_free(&uidlist->records);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen str_free(&uidlist->hdr_extensions);
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen i_free(uidlist->path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(uidlist);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainenstatic int maildir_uid_cmp(struct maildir_uidlist_rec *const *rec1,
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen struct maildir_uidlist_rec *const *rec2)
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen{
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen return (*rec1)->uid < (*rec2)->uid ? -1 :
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen (*rec1)->uid > (*rec2)->uid ? 1 : 0;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen}
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenstatic void ATTR_FORMAT(2, 3)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenmaildir_uidlist_set_corrupted(struct maildir_uidlist *uidlist,
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen const char *fmt, ...)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen{
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen va_list args;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen va_start(args, fmt);
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen if (uidlist->retry_rewind) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen "Broken or unexpectedly changed file %s "
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen "line %u: %s - re-reading from beginning",
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen uidlist->path, uidlist->read_line_count,
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen t_strdup_vprintf(fmt, args));
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen } else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box, "Broken file %s line %u: %s",
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen uidlist->path, uidlist->read_line_count,
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen t_strdup_vprintf(fmt, args));
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen va_end(args);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen}
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenstatic void maildir_uidlist_update_hdr(struct maildir_uidlist *uidlist,
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen const struct stat *st)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct maildir_index_header *mhdr = uidlist->mhdr;
bc89e663696ef6887c00a5a34c3361600304abe1Timo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen if (mhdr->uidlist_mtime == 0 && uidlist->version != UIDLIST_VERSION) {
211c638d81d382517d196ad47565e0d85012c927klemens /* upgrading from older version. don't update the
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen uidlist times until it uses the new format */
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen uidlist->recreate = TRUE;
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen return;
9e9763d04764f094c2f1bd6f36f2d83a89bd699dTimo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen mhdr->uidlist_mtime = st->st_mtime;
14c3da8abe2e666ecdb2900c8000478ef303161bTimo Sirainen mhdr->uidlist_mtime_nsecs = ST_MTIME_NSEC(*st);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen mhdr->uidlist_size = st->st_size;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen}
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainenstatic unsigned int
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainenmaildir_uidlist_records_array_delete(struct maildir_uidlist *uidlist,
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen struct maildir_uidlist_rec *rec)
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen{
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen struct maildir_uidlist_rec *const *recs, *const *pos;
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen unsigned int idx, count;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen recs = array_get(&uidlist->records, &count);
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen if (!uidlist->unsorted) {
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen pos = array_bsearch(&uidlist->records, &rec, maildir_uid_cmp);
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen i_assert(pos != NULL);
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen idx = pos - recs;
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen } else {
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen for (idx = 0; idx < count; idx++) {
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen if (recs[idx]->uid == rec->uid)
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen break;
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen }
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen i_assert(idx != count);
0dab9ad19ae7b1e3afe74d3ace2882fabb264a41Timo Sirainen }
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen array_delete(&uidlist->records, idx, 1);
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen return idx;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen}
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenstatic bool
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenmaildir_uidlist_read_extended(struct maildir_uidlist *uidlist,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen const char **line_p,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen struct maildir_uidlist_rec *rec)
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen{
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen const char *start, *line = *line_p;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen buffer_t *buf;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buf = t_buffer_create(128);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen while (*line != '\0' && *line != ':') {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen /* skip over an extension field */
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen start = line;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen while (*line != ' ' && *line != '\0') line++;
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen if (MAILDIR_UIDLIST_REC_EXT_KEY_IS_VALID(*start)) {
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen buffer_append(buf, start, line - start);
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen buffer_append_c(buf, '\0');
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen } else {
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen "Invalid extension record, removing: %s",
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen t_strdup_until(start, line));
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen uidlist->recreate = TRUE;
df9169221169d9cd8d8f49fc51ad40bed0fb6f64Timo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen while (*line == ' ') line++;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (buf->used > 0) {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen /* save the extensions */
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen buffer_append_c(buf, '\0');
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen rec->extensions = p_malloc(uidlist->record_pool, buf->used);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen memcpy(rec->extensions, buf->data, buf->used);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (*line == ':')
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen line++;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (*line == '\0')
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return FALSE;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen *line_p = line;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return TRUE;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen}
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainenstatic bool maildir_uidlist_next(struct maildir_uidlist *uidlist,
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen const char *line)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen struct maildir_uidlist_rec *rec, *old_rec, *const *recs;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen unsigned int count;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen uint32_t uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen uid = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*line >= '0' && *line <= '9') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uid = uid*10 + (*line - '0');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen line++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uid == 0 || *line != ' ') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* invalid file */
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist, "Invalid data: %s",
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen line);
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen if (uid <= uidlist->prev_read_uid) {
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen "UIDs not ordered (%u >= %u)",
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uid, uidlist->prev_read_uid);
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen if (uid >= (uint32_t)-1) {
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen maildir_uidlist_set_corrupted(uidlist,
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen "UID too high (%u)", uid);
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen return FALSE;
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen }
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen uidlist->prev_read_uid = uid;
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen if (uid <= uidlist->last_seen_uid) {
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen /* we already have this */
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen return TRUE;
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen }
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen uidlist->last_seen_uid = uid;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen
ce84075e7ad4aa67fd45d12e75feceaffc64e523Timo Sirainen if (uid >= uidlist->next_uid && uidlist->version == 1) {
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen "UID larger than next_uid (%u >= %u)",
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uid, uidlist->next_uid);
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen return FALSE;
ce84075e7ad4aa67fd45d12e75feceaffc64e523Timo Sirainen }
ce84075e7ad4aa67fd45d12e75feceaffc64e523Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen rec = p_new(uidlist->record_pool, struct maildir_uidlist_rec, 1);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen rec->uid = uid;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen rec->flags = MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*line == ' ') line++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (uidlist->version == UIDLIST_VERSION) {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen /* read extended fields */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen bool ret;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = maildir_uidlist_read_extended(uidlist, &line,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen rec);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (!ret) {
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen "Invalid extended fields: %s", line);
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen return FALSE;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
658d3e1c4b58281c35241123973f5447f812764fTimo Sirainen if (strchr(line, '/') != NULL) {
658d3e1c4b58281c35241123973f5447f812764fTimo Sirainen maildir_uidlist_set_corrupted(uidlist,
658d3e1c4b58281c35241123973f5447f812764fTimo Sirainen "%s: Broken filename at line %u: %s",
658d3e1c4b58281c35241123973f5447f812764fTimo Sirainen uidlist->path, uidlist->read_line_count, line);
10f216b59964b70548051d0a942ecea7d61c7a61Timo Sirainen return FALSE;
658d3e1c4b58281c35241123973f5447f812764fTimo Sirainen }
658d3e1c4b58281c35241123973f5447f812764fTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen old_rec = hash_table_lookup(uidlist->files, line);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (old_rec == NULL) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen /* no conflicts */
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen } else if (old_rec->uid == uid) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen /* most likely this is a record we saved ourself, but couldn't
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen update last_seen_uid because uidlist wasn't refreshed while
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen it was locked.
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen another possibility is a duplicate file record. currently
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen it would be a bug, but not that big of a deal. also perhaps
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen in future such duplicate lines could be used to update
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen extended fields. so just let it through anyway.
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen we'll waste a bit of memory here by allocating the record
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen twice, but that's not really a problem. */
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen rec->filename = old_rec->filename;
c224fff79d18480a65e9b4504b891b8ea176f5b1Timo Sirainen hash_table_update(uidlist->files, rec->filename, rec);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->unsorted = TRUE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen return TRUE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen } else {
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen /* This can happen if expunged file is moved back and the file
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen was appended to uidlist. */
3dbc59409d19dbcd3f47c041fdd2fe342647e331Timo Sirainen i_warning("%s: Duplicate file entry at line %u: "
f84e7cabe355c6416898b7ae82b7d59acc3c7fbdTimo Sirainen "%s (uid %u -> %u)%s",
3dbc59409d19dbcd3f47c041fdd2fe342647e331Timo Sirainen uidlist->path, uidlist->read_line_count, line,
f84e7cabe355c6416898b7ae82b7d59acc3c7fbdTimo Sirainen old_rec->uid, uid, uidlist->retry_rewind ?
f84e7cabe355c6416898b7ae82b7d59acc3c7fbdTimo Sirainen " - retrying by re-reading from beginning" : "");
f84e7cabe355c6416898b7ae82b7d59acc3c7fbdTimo Sirainen if (uidlist->retry_rewind)
f84e7cabe355c6416898b7ae82b7d59acc3c7fbdTimo Sirainen return FALSE;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen /* Delete the old UID */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)maildir_uidlist_records_array_delete(uidlist, old_rec);
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen /* Replace the old record with this new one */
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen *old_rec = *rec;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen rec = old_rec;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen uidlist->recreate = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen recs = array_get(&uidlist->records, &count);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (count > 0 && recs[count-1]->uid > uid) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen /* we most likely have some records in the array that we saved
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen ourself without refreshing uidlist */
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->unsorted = TRUE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen rec->filename = p_strdup(uidlist->record_pool, line);
c224fff79d18480a65e9b4504b891b8ea176f5b1Timo Sirainen hash_table_update(uidlist->files, rec->filename, rec);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen array_append(&uidlist->records, &rec, 1);
97c3cae5873e56c15357686eeeb3144896445e50Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainenstatic int
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainenmaildir_uidlist_read_v3_header(struct maildir_uidlist *uidlist,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen const char *line,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen unsigned int *uid_validity_r,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen unsigned int *next_uid_r)
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen{
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen char key;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen str_truncate(uidlist->hdr_extensions, 0);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen while (*line != '\0') {
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen const char *value;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen key = *line;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen value = ++line;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen while (*line != '\0' && *line != ' ') line++;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen value = t_strdup_until(value, line);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen switch (key) {
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen case MAILDIR_UIDLIST_HDR_EXT_UID_VALIDITY:
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_to_uint(value, uid_validity_r) < 0) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch maildir_uidlist_set_corrupted(uidlist,
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch "Invalid mailbox UID_VALIDITY: %s", value);
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch return -1;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch }
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen break;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen case MAILDIR_UIDLIST_HDR_EXT_NEXT_UID:
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_to_uint(value, next_uid_r) < 0) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch maildir_uidlist_set_corrupted(uidlist,
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch "Invalid mailbox NEXT_UID: %s", value);
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch return -1;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch }
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen break;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen case MAILDIR_UIDLIST_HDR_EXT_GUID:
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen if (guid_128_from_string(value,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen uidlist->mailbox_guid) < 0) {
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen "Invalid mailbox GUID: %s", value);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen return -1;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen }
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen uidlist->have_mailbox_guid = TRUE;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen break;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen default:
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (str_len(uidlist->hdr_extensions) > 0)
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen str_append_c(uidlist->hdr_extensions, ' ');
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen str_printfa(uidlist->hdr_extensions,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen "%c%s", key, value);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen break;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen }
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen while (*line == ' ') line++;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen }
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen return 0;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen}
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainenstatic int maildir_uidlist_read_header(struct maildir_uidlist *uidlist,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen struct istream *input)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen{
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen unsigned int uid_validity = 0, next_uid = 0;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *line;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen int ret;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen line = i_stream_read_next_line(input);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (line == NULL) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen /* I/O error / empty file */
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return input->stream_errno == 0 ? 0 : -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uidlist->read_line_count = 1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (*line < '0' || *line > '9' || line[1] != ' ') {
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen "Corrupted header (invalid version number)");
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen uidlist->version = *line - '0';
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen line += 2;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen switch (uidlist->version) {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen case 1:
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (sscanf(line, "%u %u", &uid_validity, &next_uid) != 2) {
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen "Corrupted header (version 1)");
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return 0;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen break;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen case UIDLIST_VERSION:
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen T_BEGIN {
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen ret = maildir_uidlist_read_v3_header(uidlist, line,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen &uid_validity,
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen &next_uid);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (ret < 0)
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen return 0;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen break;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen default:
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist, "Unsupported version %u",
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uidlist->version);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return 0;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (uid_validity == 0 || next_uid == 0) {
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen "Broken header (uidvalidity = %u, next_uid=%u)",
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uid_validity, next_uid);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen if (uid_validity == uidlist->uid_validity &&
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen next_uid < uidlist->hdr_next_uid) {
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen maildir_uidlist_set_corrupted(uidlist,
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen "next_uid header was lowered (%u -> %u)",
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen uidlist->hdr_next_uid, next_uid);
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen return 0;
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen }
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->uid_validity = uid_validity;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->next_uid = next_uid;
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen uidlist->hdr_next_uid = next_uid;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen}
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainenstatic void maildir_uidlist_records_sort_by_uid(struct maildir_uidlist *uidlist)
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen{
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&uidlist->records, maildir_uid_cmp);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->unsorted = FALSE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen}
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainenstatic int
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainenmaildir_uidlist_update_read(struct maildir_uidlist *uidlist,
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen bool *retry_r, bool try_retry)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *line;
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen uint32_t orig_next_uid, orig_uid_validity;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream *input;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct stat st;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uoff_t last_read_offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int fd, ret;
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen bool readonly = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen *retry_r = FALSE;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (uidlist->fd == -1) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen fd = nfs_safe_open(uidlist->path, O_RDWR);
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen if (fd == -1 && errno == EACCES) {
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen fd = nfs_safe_open(uidlist->path, O_RDONLY);
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen readonly = TRUE;
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (fd == -1) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (errno != ENOENT) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen "open(%s) failed: %m", uidlist->path);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen last_read_offset = 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen } else {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen /* the file was updated */
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen fd = uidlist->fd;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (lseek(fd, 0, SEEK_SET) < 0) {
5b237a9d400a434920c8fd77ae53e6b44c38d3fbTimo Sirainen if (errno == ESTALE && try_retry) {
5b237a9d400a434920c8fd77ae53e6b44c38d3fbTimo Sirainen *retry_r = TRUE;
5b237a9d400a434920c8fd77ae53e6b44c38d3fbTimo Sirainen return -1;
5b237a9d400a434920c8fd77ae53e6b44c38d3fbTimo Sirainen }
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen "lseek(%s) failed: %m", uidlist->path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->fd = -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->fd_ino = 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen last_read_offset = uidlist->last_read_offset;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->last_read_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fstat(fd, &st) < 0) {
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen if (errno == ESTALE && try_retry) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen *retry_r = TRUE;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return -1;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen "fstat(%s) failed: %m", uidlist->path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen if (uidlist->record_pool == NULL) {
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen uidlist->record_pool =
588f592a98fca95a10aaccdc76a589558e9ba125Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING
588f592a98fca95a10aaccdc76a589558e9ba125Timo Sirainen "uidlist record_pool",
3a282e21c69b9cad1b5f9359ec3aebd3c8b8e901Timo Sirainen nearest_power(st.st_size -
3a282e21c69b9cad1b5f9359ec3aebd3c8b8e901Timo Sirainen st.st_size/8));
3a282e21c69b9cad1b5f9359ec3aebd3c8b8e901Timo Sirainen }
3a282e21c69b9cad1b5f9359ec3aebd3c8b8e901Timo Sirainen
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi input = i_stream_create_fd(fd, (size_t)-1);
5d773f4692c09cb3e2d68a6a8ca7fd05f692ebb2Timo Sirainen i_stream_seek(input, last_read_offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen orig_uid_validity = uidlist->uid_validity;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen orig_next_uid = uidlist->next_uid;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen ret = input->v_offset != 0 ? 1 :
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen maildir_uidlist_read_header(uidlist, input);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (ret > 0) {
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen uidlist->prev_read_uid = 0;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen uidlist->change_counter++;
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen uidlist->retry_rewind = last_read_offset != 0 && try_retry;
b06bfeaa9bb367b72edd51672c33e24d33d8ff1bTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->read_records_count++;
819e20e6f108db20751e19784ee5a091b3f50046Timo Sirainen uidlist->read_line_count++;
0360636eced27e96661f210828d1203871e6c47cTimo Sirainen if (!maildir_uidlist_next(uidlist, line)) {
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen if (!uidlist->retry_rewind)
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen ret = 0;
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen else {
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen ret = -1;
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen *retry_r = TRUE;
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen uidlist->retry_rewind = FALSE;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (input->stream_errno != 0)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen ret = -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (uidlist->unsorted) {
b6ccb2a38287c42aa53f66a927a6ada9d324b0beTimo Sirainen uidlist->recreate_on_change = TRUE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen maildir_uidlist_records_sort_by_uid(uidlist);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (uidlist->next_uid <= uidlist->prev_read_uid)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->next_uid = uidlist->prev_read_uid + 1;
430acc18d409c92da20be46ef35dc6f1d2a855d2Timo Sirainen if (ret > 0 && uidlist->uid_validity != orig_uid_validity &&
430acc18d409c92da20be46ef35dc6f1d2a855d2Timo Sirainen orig_uid_validity != 0) {
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen uidlist->recreate = TRUE;
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen } else if (ret > 0 && uidlist->next_uid < orig_next_uid) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen "%s: next_uid was lowered (%u -> %u, hdr=%u)",
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->path, orig_next_uid,
5b440b4d921cb1a36d74b4082599ccd3bb0f0401Timo Sirainen uidlist->next_uid, uidlist->hdr_next_uid);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->recreate = TRUE;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->next_uid = orig_next_uid;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if (ret == 0) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen /* file is broken */
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink(uidlist->path);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen } else if (ret > 0) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen /* success */
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen if (readonly)
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen uidlist->recreate_on_change = TRUE;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen uidlist->fd = fd;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen uidlist->fd_dev = st.st_dev;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen uidlist->fd_ino = st.st_ino;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->fd_size = st.st_size;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->last_read_offset = input->v_offset;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen maildir_uidlist_update_hdr(uidlist, &st);
a6249a80d437771867cf654ae9d11f8418c9d07bTimo Sirainen } else if (!*retry_r) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen /* I/O error */
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen if (input->stream_errno == ESTALE && try_retry)
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen *retry_r = TRUE;
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen "read(%s) failed: %s", uidlist->path,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen i_stream_get_error(input));
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen }
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->last_read_offset = 0;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_destroy(&input);
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen if (ret <= 0) {
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen if (close(fd) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen "close(%s) failed: %m", uidlist->path);
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen }
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainenstatic int
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenmaildir_uidlist_stat(struct maildir_uidlist *uidlist, struct stat *st_r)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mail_storage *storage = uidlist->box->storage;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (storage->set->mail_nfs_storage) {
4f44284b96302c0a18203e2ac1243aeb193c6840Timo Sirainen nfs_flush_file_handle_cache(uidlist->path);
4f44284b96302c0a18203e2ac1243aeb193c6840Timo Sirainen nfs_flush_attr_cache_unlocked(uidlist->path);
4f44284b96302c0a18203e2ac1243aeb193c6840Timo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (nfs_safe_stat(uidlist->path, st_r) < 0) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (errno != ENOENT) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen "stat(%s) failed: %m", uidlist->path);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return 1;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen}
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenstatic int
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenmaildir_uidlist_has_changed(struct maildir_uidlist *uidlist, bool *recreated_r)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mail_storage *storage = uidlist->box->storage;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen struct stat st;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen int ret;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen *recreated_r = FALSE;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
6f1936d4f5424f2ce766b62ef41f4173ecf5e33bTimo Sirainen if ((ret = maildir_uidlist_stat(uidlist, &st)) < 0)
6f1936d4f5424f2ce766b62ef41f4173ecf5e33bTimo Sirainen return -1;
6f1936d4f5424f2ce766b62ef41f4173ecf5e33bTimo Sirainen if (ret == 0) {
6f1936d4f5424f2ce766b62ef41f4173ecf5e33bTimo Sirainen *recreated_r = TRUE;
6f1936d4f5424f2ce766b62ef41f4173ecf5e33bTimo Sirainen return 1;
6f1936d4f5424f2ce766b62ef41f4173ecf5e33bTimo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (st.st_ino != uidlist->fd_ino ||
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen !CMP_DEV_T(st.st_dev, uidlist->fd_dev)) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen /* file recreated */
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen *recreated_r = TRUE;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 1;
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen }
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (storage->set->mail_nfs_storage) {
54cb36f32da0f2b1225a62e9e5717d521e21aa99Timo Sirainen /* NFS: either the file hasn't been changed, or it has already
54cb36f32da0f2b1225a62e9e5717d521e21aa99Timo Sirainen been deleted and the inodes just happen to be the same.
54cb36f32da0f2b1225a62e9e5717d521e21aa99Timo Sirainen check if the fd is still valid. */
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (fstat(uidlist->fd, &st) < 0) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (errno == ESTALE) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen *recreated_r = TRUE;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return 1;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen }
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen "fstat(%s) failed: %m", uidlist->path);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return -1;
54cb36f32da0f2b1225a62e9e5717d521e21aa99Timo Sirainen }
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen }
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen if (st.st_size != uidlist->fd_size) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen /* file modified but not recreated */
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen } else {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen /* unchanged */
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen}
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainenstatic int maildir_uidlist_open_latest(struct maildir_uidlist *uidlist)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen{
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen bool recreated;
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen int ret;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen if (uidlist->fd != -1) {
4f44284b96302c0a18203e2ac1243aeb193c6840Timo Sirainen ret = maildir_uidlist_has_changed(uidlist, &recreated);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (ret <= 0) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (UIDLIST_IS_LOCKED(uidlist))
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen uidlist->locked_refresh = TRUE;
221249518003d405ea16251a86d420dc5b921357Timo Sirainen return ret < 0 ? -1 : 1;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen if (!recreated)
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen return 0;
05f323615730bc20d5e9f2c85b01465f88af2092Timo Sirainen maildir_uidlist_reset(uidlist);
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen }
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen uidlist->fd = nfs_safe_open(uidlist->path, O_RDWR);
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen if (uidlist->fd == -1 && errno == EACCES) {
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen uidlist->fd = nfs_safe_open(uidlist->path, O_RDONLY);
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen uidlist->recreate_on_change = TRUE;
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen }
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen if (uidlist->fd == -1 && errno != ENOENT) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen "open(%s) failed: %m", uidlist->path);
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen return -1;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen return 0;
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen}
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainenint maildir_uidlist_refresh(struct maildir_uidlist *uidlist)
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen{
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen unsigned int i;
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen bool retry;
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen int ret;
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen if (maildir_uidlist_open_latest(uidlist) < 0)
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen return -1;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen for (i = 0; ; i++) {
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen ret = maildir_uidlist_update_read(uidlist, &retry,
c485524d09c650ff6e6c552129d4257ac6145a8bTimo Sirainen i < UIDLIST_ESTALE_RETRY_COUNT);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (!retry)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen break;
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen /* ESTALE - try reopening and rereading */
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen maildir_uidlist_close(uidlist);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (ret >= 0) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->initial_read = TRUE;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->initial_hdr_read = TRUE;
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen if (UIDLIST_IS_LOCKED(uidlist))
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen uidlist->locked_refresh = TRUE;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (!uidlist->have_mailbox_guid) {
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen uidlist->recreate = TRUE;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen (void)maildir_uidlist_update(uidlist);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return ret;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenint maildir_uidlist_refresh_fast_init(struct maildir_uidlist *uidlist)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen const struct maildir_index_header *mhdr = uidlist->mhdr;
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mail_index *index = uidlist->box->index;
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen struct mail_index_view *view;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen const struct mail_index_header *hdr;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen struct stat st;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen int ret;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen i_assert(UIDLIST_IS_LOCKED(uidlist));
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (uidlist->fd != -1)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return maildir_uidlist_refresh(uidlist);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if ((ret = maildir_uidlist_stat(uidlist, &st)) < 0)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return ret;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
8c94614f795530b2cbe70e5e828da121f2ddbee2Timo Sirainen if (ret > 0 && st.st_size == mhdr->uidlist_size &&
003dcf6f58919f7c64d9307b6de829b0259bb592Timo Sirainen st.st_mtime == (time_t)mhdr->uidlist_mtime &&
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen ST_NTIMES_EQUAL(ST_MTIME_NSEC(st), mhdr->uidlist_mtime_nsecs) &&
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen (!mail_index_is_in_memory(index) || st.st_mtime < ioloop_time-1)) {
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen /* index is up-to-date. look up the uidvalidity and next-uid
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen from it. we'll need to create a new view temporarily to
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen make sure we get the latest values. */
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen view = mail_index_view_open(index);
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen hdr = mail_index_get_header(view);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->uid_validity = hdr->uid_validity;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->next_uid = hdr->next_uid;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->initial_hdr_read = TRUE;
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen mail_index_view_close(&view);
fcadc92fa095335d1119b161584e7fa8568f9267Timo Sirainen
fcadc92fa095335d1119b161584e7fa8568f9267Timo Sirainen if (UIDLIST_IS_LOCKED(uidlist))
fcadc92fa095335d1119b161584e7fa8568f9267Timo Sirainen uidlist->locked_refresh = TRUE;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return 1;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen } else {
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return maildir_uidlist_refresh(uidlist);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen}
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainenstatic int
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainenmaildir_uid_bsearch_cmp(const uint32_t *uidp,
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen struct maildir_uidlist_rec *const *recp)
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen{
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen return *uidp < (*recp)->uid ? -1 :
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen *uidp > (*recp)->uid ? 1 : 0;
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen}
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainenstatic int
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenmaildir_uidlist_lookup_rec(struct maildir_uidlist *uidlist, uint32_t uid,
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen struct maildir_uidlist_rec **rec_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen struct maildir_uidlist_rec *const *pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen if (!uidlist->initial_read) {
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen /* first time we need to read uidlist */
4f44284b96302c0a18203e2ac1243aeb193c6840Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0)
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return -1;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen pos = array_bsearch(&uidlist->records, &uid,
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen maildir_uid_bsearch_cmp);
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen if (pos == NULL) {
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen *rec_r = NULL;
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen *rec_r = *pos;
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainenint maildir_uidlist_lookup(struct maildir_uidlist *uidlist, uint32_t uid,
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen enum maildir_uidlist_rec_flag *flags_r,
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen const char **fname_r)
fd1a173038402c968f82d6b19b8b2e029bbcee45Timo Sirainen{
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen struct maildir_uidlist_rec *rec;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen int ret;
fd1a173038402c968f82d6b19b8b2e029bbcee45Timo Sirainen
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen if ((ret = maildir_uidlist_lookup_rec(uidlist, uid, &rec)) <= 0)
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return ret;
fd1a173038402c968f82d6b19b8b2e029bbcee45Timo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen *flags_r = rec->flags;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen *fname_r = rec->filename;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return 1;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen}
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenconst char *
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenmaildir_uidlist_lookup_ext(struct maildir_uidlist *uidlist, uint32_t uid,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen enum maildir_uidlist_rec_ext_key key)
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen{
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen struct maildir_uidlist_rec *rec;
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen const unsigned char *p;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen int ret;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
e7912167935f67b3dc68c80bf80d719bb1cdc533Timo Sirainen ret = maildir_uidlist_lookup_rec(uidlist, uid, &rec);
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen if (ret <= 0 || rec->extensions == NULL)
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return NULL;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
c31661baf87b506c2a90a1fca02968cf82e448bbTimo Sirainen p = rec->extensions;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen while (*p != '\0') {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen /* <key><value>\0 */
4efba37e4f27b93832f6147c3a353d6d22c855c7Timo Sirainen if (*p == (unsigned char)key)
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen return (const char *)p + 1;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen p += strlen((const char *)p) + 1;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return NULL;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen}
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenuint32_t maildir_uidlist_get_uid_validity(struct maildir_uidlist *uidlist)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return uidlist->uid_validity;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainenuint32_t maildir_uidlist_get_next_uid(struct maildir_uidlist *uidlist)
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainen{
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return !uidlist->initial_hdr_read ? 0 : uidlist->next_uid;
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainen}
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainen
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainenint maildir_uidlist_get_mailbox_guid(struct maildir_uidlist *uidlist,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_t mailbox_guid)
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen{
1a8b6bb75a7e10e0a44a98848f478f16972f13e7Timo Sirainen if (!uidlist->initial_hdr_read) {
1a8b6bb75a7e10e0a44a98848f478f16972f13e7Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0)
1a8b6bb75a7e10e0a44a98848f478f16972f13e7Timo Sirainen return -1;
1a8b6bb75a7e10e0a44a98848f478f16972f13e7Timo Sirainen }
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (!uidlist->have_mailbox_guid) {
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen uidlist->recreate = TRUE;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (maildir_uidlist_update(uidlist) < 0)
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen return -1;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen }
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen memcpy(mailbox_guid, uidlist->mailbox_guid, GUID_128_SIZE);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen return 0;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen}
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainenvoid maildir_uidlist_set_mailbox_guid(struct maildir_uidlist *uidlist,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen const guid_128_t mailbox_guid)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen{
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (memcmp(uidlist->mailbox_guid, mailbox_guid,
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen sizeof(uidlist->mailbox_guid)) != 0) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen memcpy(uidlist->mailbox_guid, mailbox_guid,
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen sizeof(uidlist->mailbox_guid));
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uidlist->recreate = TRUE;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen}
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainenvoid maildir_uidlist_set_uid_validity(struct maildir_uidlist *uidlist,
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainen uint32_t uid_validity)
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen{
223e07c3178289fe7e8ec62af7655657ee236dcfTimo Sirainen i_assert(uid_validity != 0);
223e07c3178289fe7e8ec62af7655657ee236dcfTimo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (uid_validity != uidlist->uid_validity) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uidlist->uid_validity = uid_validity;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uidlist->recreate = TRUE;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen}
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainenvoid maildir_uidlist_set_next_uid(struct maildir_uidlist *uidlist,
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainen uint32_t next_uid, bool force)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (uidlist->next_uid < next_uid || force) {
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen i_assert(next_uid != 0);
6b77095184aeb8a9976a74fa9ba1a06740f40d0eTimo Sirainen uidlist->next_uid = next_uid;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uidlist->recreate = TRUE;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic void
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainenmaildir_uidlist_rec_set_ext(struct maildir_uidlist_rec *rec, pool_t pool,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen enum maildir_uidlist_rec_ext_key key,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen const char *value)
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen{
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen const unsigned char *p;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen buffer_t *buf;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen /* copy existing extensions, except for the one we're updating */
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buf = t_buffer_create(128);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen if (rec->extensions != NULL) {
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen p = rec->extensions;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen while (*p != '\0') {
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen /* <key><value>\0 */
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen i_assert(MAILDIR_UIDLIST_REC_EXT_KEY_IS_VALID(*p));
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen len = strlen((const char *)p) + 1;
4efba37e4f27b93832f6147c3a353d6d22c855c7Timo Sirainen if (*p != (unsigned char)key)
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen buffer_append(buf, p, len);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen p += len;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen }
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen }
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen if (value != NULL) {
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen buffer_append_c(buf, key);
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen buffer_append(buf, value, strlen(value) + 1);
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen }
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen buffer_append_c(buf, '\0');
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen rec->extensions = p_malloc(pool, buf->used);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen memcpy(rec->extensions, buf->data, buf->used);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(4)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenmaildir_uidlist_set_ext_internal(struct maildir_uidlist *uidlist, uint32_t uid,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen enum maildir_uidlist_rec_ext_key key,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen const char *value)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen struct maildir_uidlist_rec *rec;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen int ret;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen i_assert(MAILDIR_UIDLIST_REC_EXT_KEY_IS_VALID(key));
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen ret = maildir_uidlist_lookup_rec(uidlist, uid, &rec);
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (ret <= 0) {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (ret < 0)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen return;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen /* maybe it's a new message */
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen return;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (maildir_uidlist_lookup_rec(uidlist, uid, &rec) <= 0) {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen /* message is already expunged, ignore */
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen return;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen }
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen }
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen maildir_uidlist_rec_set_ext(rec, uidlist->record_pool,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen key, value);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (rec->uid != (uint32_t)-1) {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen /* message already exists in uidlist, need to recreate it */
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen uidlist->recreate = TRUE;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen }
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen}
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenvoid maildir_uidlist_set_ext(struct maildir_uidlist *uidlist, uint32_t uid,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen enum maildir_uidlist_rec_ext_key key,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen const char *value)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen{
90814c0276d9f7bd6650e430b8cb64a8918ad4b3Timo Sirainen maildir_uidlist_set_ext_internal(uidlist, uid, key, value);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen}
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenvoid maildir_uidlist_unset_ext(struct maildir_uidlist *uidlist, uint32_t uid,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen enum maildir_uidlist_rec_ext_key key)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen{
90814c0276d9f7bd6650e430b8cb64a8918ad4b3Timo Sirainen maildir_uidlist_set_ext_internal(uidlist, uid, key, NULL);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen}
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainenstatic void
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainenmaildir_uidlist_generate_uid_validity(struct maildir_uidlist *uidlist)
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen{
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen const struct mail_index_header *hdr;
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen if (uidlist->box->opened) {
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen hdr = mail_index_get_header(uidlist->box->view);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (hdr->uid_validity != 0) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uidlist->uid_validity = hdr->uid_validity;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen return;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uidlist->uid_validity =
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen maildir_get_uidvalidity_next(uidlist->box->list);
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen}
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainenstatic int maildir_uidlist_write_fd(struct maildir_uidlist *uidlist, int fd,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen const char *path, unsigned int first_idx,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uoff_t *file_size_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mail_storage *storage = uidlist->box->storage;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist_iter_ctx *iter;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen struct ostream *output;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen struct maildir_uidlist_rec *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen string_t *str;
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen const unsigned char *p;
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen const char *strp;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
d67ac5f76cc02c227f4997878bb4aef48ee298faTimo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen i_assert(fd != -1);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen output = o_stream_create_fd_file(fd, (uoff_t)-1, FALSE);
47025fa2781c7862957690e21fc9e1aa2f1b6f60Timo Sirainen o_stream_cork(output);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen str = t_str_new(512);
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (output->offset == 0) {
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen i_assert(first_idx == 0);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->version = UIDLIST_VERSION;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen if (uidlist->uid_validity == 0)
ec9161e5061a34f0262ccbbf7760ee933d409167Timo Sirainen maildir_uidlist_generate_uid_validity(uidlist);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (!uidlist->have_mailbox_guid)
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_generate(uidlist->mailbox_guid);
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen
223e07c3178289fe7e8ec62af7655657ee236dcfTimo Sirainen i_assert(uidlist->next_uid > 0);
4cc8a792108e1c115c1c6c9eb61746b31f0205dbTimo Sirainen str_printfa(str, "%u %c%u %c%u %c%s", uidlist->version,
4cc8a792108e1c115c1c6c9eb61746b31f0205dbTimo Sirainen MAILDIR_UIDLIST_HDR_EXT_UID_VALIDITY,
4cc8a792108e1c115c1c6c9eb61746b31f0205dbTimo Sirainen uidlist->uid_validity,
4cc8a792108e1c115c1c6c9eb61746b31f0205dbTimo Sirainen MAILDIR_UIDLIST_HDR_EXT_NEXT_UID,
4cc8a792108e1c115c1c6c9eb61746b31f0205dbTimo Sirainen uidlist->next_uid,
4cc8a792108e1c115c1c6c9eb61746b31f0205dbTimo Sirainen MAILDIR_UIDLIST_HDR_EXT_GUID,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen guid_128_to_string(uidlist->mailbox_guid));
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (str_len(uidlist->hdr_extensions) > 0) {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen str_append_c(str, ' ');
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen str_append_str(str, uidlist->hdr_extensions);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen str_append_c(str, '\n');
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen iter = maildir_uidlist_iter_init(uidlist);
bb592fc58fe5c3e81ad941637fbb30d1d1cd8694Timo Sirainen i_assert(first_idx <= array_count(&uidlist->records));
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen iter->next += first_idx;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen while (maildir_uidlist_iter_next_rec(iter, &rec)) {
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen uidlist->read_records_count++;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen str_truncate(str, 0);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen str_printfa(str, "%u", rec->uid);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (rec->extensions != NULL) {
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen for (p = rec->extensions; *p != '\0'; ) {
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen i_assert(MAILDIR_UIDLIST_REC_EXT_KEY_IS_VALID(*p));
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen len = strlen((const char *)p);
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen str_append_c(str, ' ');
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen str_append_n(str, p, len);
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen p += len + 1;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen }
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen str_append(str, " :");
db5fdf605555d43ca7abeaeb9cba0dcb178f2688Aki Tuomi strp = strchr(rec->filename, *MAILDIR_INFO_SEP_S);
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen if (strp == NULL)
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen str_append(str, rec->filename);
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen else
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen str_append_n(str, rec->filename, strp - rec->filename);
6af9d209ee997d624aecbaf4a0bcd0ca7d60c31aTimo Sirainen str_append_c(str, '\n');
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen maildir_uidlist_iter_deinit(&iter);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ad9afb64630511d5e25bc5bc11c5304986156928Timo Sirainen if (o_stream_finish(output) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box, "write(%s) failed: %s",
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi path, o_stream_get_error(output));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_unref(&output);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen *file_size_r = output->offset;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen o_stream_unref(&output);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen if (fdatasync(fd) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
73fd4a877d9d2517c2ba7438c79a4cf42c701352Timo Sirainen "fdatasync(%s) failed: %m", path);
39344e449ff55820f8620c0fa943362f90ff9f6aTimo Sirainen return -1;
39344e449ff55820f8620c0fa943362f90ff9f6aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainenstatic void
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainenmaildir_uidlist_records_drop_expunges(struct maildir_uidlist *uidlist)
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen{
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen struct mail_index_view *view;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen struct maildir_uidlist_rec *const *recs;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen ARRAY_TYPE(maildir_uidlist_rec_p) new_records;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen const struct mail_index_header *hdr;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen const struct mail_index_record *rec;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen unsigned int i, count;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen uint32_t seq;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
67b328e6950f41c8d680af4775639c2c689f43cdTimo Sirainen /* we could get here when opening and locking mailbox,
67b328e6950f41c8d680af4775639c2c689f43cdTimo Sirainen before index files have been opened. */
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen if (!uidlist->box->opened)
67b328e6950f41c8d680af4775639c2c689f43cdTimo Sirainen return;
67b328e6950f41c8d680af4775639c2c689f43cdTimo Sirainen
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen mail_index_refresh(uidlist->box->index);
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen view = mail_index_view_open(uidlist->box->index);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen count = array_count(&uidlist->records);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen hdr = mail_index_get_header(view);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen if (count * UIDLIST_COMPRESS_PERCENTAGE / 100 <= hdr->messages_count) {
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen /* too much trouble to be worth it */
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen mail_index_view_close(&view);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen return;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen }
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen i_array_init(&new_records, hdr->messages_count + 64);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen recs = array_get(&uidlist->records, &count);
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen for (i = 0, seq = 1; i < count && seq <= hdr->messages_count; ) {
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen rec = mail_index_lookup(view, seq);
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen if (recs[i]->uid < rec->uid) {
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen /* expunged entry */
d55fb5fbf2dc0601fc34dbd26221369b0cedb5daTimo Sirainen hash_table_remove(uidlist->files, recs[i]->filename);
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen i++;
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen } else if (recs[i]->uid > rec->uid) {
95c8129d63a2e243402d67f9c93e532beebee394Timo Sirainen /* index isn't up to date. we're probably just
95c8129d63a2e243402d67f9c93e532beebee394Timo Sirainen syncing it here. ignore this entry. */
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen seq++;
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen } else {
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen array_append(&new_records, &recs[i], 1);
f63b54b0c5fa2717443fd3a96f37119fdceb39e9Timo Sirainen seq++; i++;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen }
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen }
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen /* drop messages expunged at the end of index */
d55fb5fbf2dc0601fc34dbd26221369b0cedb5daTimo Sirainen while (i < count && recs[i]->uid < hdr->next_uid) {
d55fb5fbf2dc0601fc34dbd26221369b0cedb5daTimo Sirainen hash_table_remove(uidlist->files, recs[i]->filename);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen i++;
d55fb5fbf2dc0601fc34dbd26221369b0cedb5daTimo Sirainen }
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen /* view might not be completely up-to-date, so preserve any
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen messages left */
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen for (; i < count; i++)
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen array_append(&new_records, &recs[i], 1);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen array_free(&uidlist->records);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen uidlist->records = new_records;
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen mail_index_view_close(&view);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen}
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
0441036bcde07d0ee015f06967a6579e3e1d5b9bTimo Sirainenstatic int maildir_uidlist_recreate(struct maildir_uidlist *uidlist)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen struct mailbox *box = uidlist->box;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const struct mailbox_permissions *perm = mailbox_get_permissions(box);
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen const char *control_dir, *temp_path;
ee1681a053a515048d82fb57c366c26696fa0a33Timo Sirainen struct stat st;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen mode_t old_mask;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uoff_t file_size;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen int i, fd, ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen i_assert(uidlist->initial_read);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen maildir_uidlist_records_drop_expunges(uidlist);
9405e52abbd62fa7f57fbd86943743e1959fe7acTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_CONTROL,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &control_dir) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen i_unreached();
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen temp_path = t_strconcat(control_dir,
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen "/" MAILDIR_UIDLIST_NAME ".tmp", NULL);
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen for (i = 0;; i++) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen old_mask = umask(0777 & ~perm->file_create_mode);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen fd = open(temp_path, O_RDWR | O_CREAT | O_TRUNC, 0777);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen umask(old_mask);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (fd != -1)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen "open(%s, O_CREAT) failed: %m", temp_path);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* the control dir doesn't exist. create it unless the whole
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen mailbox was just deleted. */
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen if (!maildir_set_deleted(uidlist->box))
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (perm->file_create_gid != (gid_t)-1 &&
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (errno == EPERM) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "%s",
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen eperm_error_get_chgrp("fchown", temp_path,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen perm->file_create_gid,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen perm->file_create_gid_origin));
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen } else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen "fchown(%s) failed: %m", temp_path);
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen }
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen uidlist->read_records_count = 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen ret = maildir_uidlist_write_fd(uidlist, fd, temp_path, 0, &file_size);
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen if (ret == 0) {
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen if (rename(temp_path, uidlist->path) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen "rename(%s, %s) failed: %m",
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen temp_path, uidlist->path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
275cc4c040899c132b2acbe2fcac48ba4c1abbcfTimo Sirainen if (ret < 0)
275cc4c040899c132b2acbe2fcac48ba4c1abbcfTimo Sirainen i_unlink(temp_path);
275cc4c040899c132b2acbe2fcac48ba4c1abbcfTimo Sirainen else if (fstat(fd, &st) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen "fstat(%s) failed: %m", temp_path);
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen ret = -1;
ac432b21f61d8c97f3459134b180ed13b90704e5Timo Sirainen } else if (file_size != (uoff_t)st.st_size) {
ac432b21f61d8c97f3459134b180ed13b90704e5Timo Sirainen i_assert(!file_dotlock_is_locked(uidlist->dotlock));
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen "Maildir uidlist dotlock overridden: %s",
ac432b21f61d8c97f3459134b180ed13b90704e5Timo Sirainen uidlist->path);
ac432b21f61d8c97f3459134b180ed13b90704e5Timo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
3f88671f6d3d54d1e5fd090c2d1cbd602df0d09bTimo Sirainen maildir_uidlist_close(uidlist);
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen uidlist->fd = fd;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen uidlist->fd_dev = st.st_dev;
de7611687432b9560bdd31a4969609e7b68a5b83Timo Sirainen uidlist->fd_ino = st.st_ino;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->fd_size = st.st_size;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uidlist->last_read_offset = st.st_size;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen uidlist->recreate = FALSE;
b6ccb2a38287c42aa53f66a927a6ada9d324b0beTimo Sirainen uidlist->recreate_on_change = FALSE;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen uidlist->have_mailbox_guid = TRUE;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen maildir_uidlist_update_hdr(uidlist, &st);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
3d962035558bec7ff88408a167c877b270138d25Timo Sirainen if (ret < 0)
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainenint maildir_uidlist_update(struct maildir_uidlist *uidlist)
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen{
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen int ret;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen if (!uidlist->recreate)
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen return 0;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen if (maildir_uidlist_lock(uidlist) <= 0)
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen return -1;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen ret = maildir_uidlist_recreate(uidlist);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen maildir_uidlist_unlock(uidlist);
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen return ret;
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen}
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainen
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainenstatic bool maildir_uidlist_want_compress(struct maildir_uidlist_sync_ctx *ctx)
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen{
7133574ad9c46d79a6b741adfc5b0ecc04cd9298Timo Sirainen unsigned int min_rewrite_count;
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen if (!ctx->uidlist->locked_refresh)
d8b23843fb938c0a8f19f4abdb6c2a04b898a2b1Timo Sirainen return FALSE;
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen if (ctx->uidlist->recreate)
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen return TRUE;
d8b23843fb938c0a8f19f4abdb6c2a04b898a2b1Timo Sirainen
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen min_rewrite_count =
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen (ctx->uidlist->read_records_count + ctx->new_files_count) *
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen UIDLIST_COMPRESS_PERCENTAGE / 100;
7133574ad9c46d79a6b741adfc5b0ecc04cd9298Timo Sirainen return min_rewrite_count >= array_count(&ctx->uidlist->records);
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen}
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainenstatic bool maildir_uidlist_want_recreate(struct maildir_uidlist_sync_ctx *ctx)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen{
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen struct maildir_uidlist *uidlist = ctx->uidlist;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
fcadc92fa095335d1119b161584e7fa8568f9267Timo Sirainen if (!uidlist->locked_refresh || !uidlist->initial_read)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return FALSE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen if (ctx->finish_change_counter != uidlist->change_counter)
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen return TRUE;
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen if (uidlist->fd == -1 || uidlist->version != UIDLIST_VERSION ||
c0bfb67ba32064347bac3241f1aac9b8a809e2f1Timo Sirainen !uidlist->have_mailbox_guid)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return TRUE;
fe761f466e2c0c49445115aa123c77097c0eaf5cTimo Sirainen return maildir_uidlist_want_compress(ctx);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen}
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
81c7a6e414a6d1c31f65cc977feda823b586d263Timo Sirainenstatic int maildir_uidlist_sync_update(struct maildir_uidlist_sync_ctx *ctx)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen{
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen struct maildir_uidlist *uidlist = ctx->uidlist;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen struct stat st;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen uoff_t file_size;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
b6ccb2a38287c42aa53f66a927a6ada9d324b0beTimo Sirainen if (maildir_uidlist_want_recreate(ctx) || uidlist->recreate_on_change)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return maildir_uidlist_recreate(uidlist);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen if (!uidlist->locked_refresh || uidlist->fd == -1) {
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen /* make sure we have the latest file (e.g. NOREFRESH used) */
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen i_assert(uidlist->initial_hdr_read);
aba2f05e938a7f635b3f114d56c7c3413ee858feTimo Sirainen if (maildir_uidlist_open_latest(uidlist) < 0)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return -1;
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen if (uidlist->recreate_on_change)
a0b92d47480ac4135b5dec900c4358defbb3e0e6Timo Sirainen return maildir_uidlist_recreate(uidlist);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen i_assert(ctx->first_unwritten_pos != UINT_MAX);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (lseek(uidlist->fd, 0, SEEK_END) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen "lseek(%s) failed: %m", uidlist->path);
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (maildir_uidlist_write_fd(uidlist, uidlist->fd, uidlist->path,
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen ctx->first_unwritten_pos, &file_size) < 0)
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return -1;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (fstat(uidlist->fd, &st) < 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen "fstat(%s) failed: %m", uidlist->path);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return -1;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen }
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if ((uoff_t)st.st_size != file_size) {
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen i_warning("%s: file size changed unexpectedly after write",
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->path);
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen } else if (uidlist->locked_refresh) {
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->fd_size = st.st_size;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen uidlist->last_read_offset = st.st_size;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen maildir_uidlist_update_hdr(uidlist, &st);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen return 0;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen}
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainenstatic void maildir_uidlist_mark_all(struct maildir_uidlist *uidlist,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool nonsynced)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen struct maildir_uidlist_rec **recs;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen unsigned int i, count;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen recs = array_get_modifiable(&uidlist->records, &count);
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen if (nonsynced) {
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen for (i = 0; i < count; i++)
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen recs[i]->flags |= MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen } else {
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen for (i = 0; i < count; i++)
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen recs[i]->flags &= ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen }
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen}
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainenstatic int maildir_uidlist_sync_lock(struct maildir_uidlist *uidlist,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen enum maildir_uidlist_sync_flags sync_flags,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen bool *locked_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen bool nonblock, refresh;
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen int ret;
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen *locked_r = FALSE;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if ((sync_flags & MAILDIR_UIDLIST_SYNC_NOLOCK) != 0) {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0)
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return -1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return 1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen nonblock = (sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) != 0;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen refresh = (sync_flags & MAILDIR_UIDLIST_SYNC_NOREFRESH) == 0;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen ret = maildir_uidlist_lock_timeout(uidlist, nonblock, refresh, refresh);
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (ret <= 0) {
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if (ret < 0 || !nonblock)
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen return ret;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen /* couldn't lock it */
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen if ((sync_flags & MAILDIR_UIDLIST_SYNC_FORCE) == 0)
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen return 0;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen /* forcing the sync anyway */
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (maildir_uidlist_refresh(uidlist) < 0)
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen return -1;
7c65a07e04f28f2a881d83989f85f9ad0e87a7b4Timo Sirainen } else {
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen *locked_r = TRUE;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen }
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return 1;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen}
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenvoid maildir_uidlist_set_all_nonsynced(struct maildir_uidlist *uidlist)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen{
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen maildir_uidlist_mark_all(uidlist, TRUE);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen}
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainenint maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen enum maildir_uidlist_sync_flags sync_flags,
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen struct maildir_uidlist_sync_ctx **sync_ctx_r)
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen{
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen struct maildir_uidlist_sync_ctx *ctx;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen bool locked;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen int ret;
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen ret = maildir_uidlist_sync_lock(uidlist, sync_flags, &locked);
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen if (ret <= 0)
ba3d9eeb0bec6ed8465d68fa2480ad085559b580Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen *sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->uidlist = uidlist;
e32cf1b4430c4a5f28c9b5bb8b1366e7b06ed68dTimo Sirainen ctx->sync_flags = sync_flags;
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen ctx->partial = !locked ||
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen (sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0;
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen ctx->locked = locked;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ctx->first_unwritten_pos = UINT_MAX;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ctx->first_new_pos = UINT_MAX;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
e32cf1b4430c4a5f28c9b5bb8b1366e7b06ed68dTimo Sirainen if (ctx->partial) {
8925c5450daddcdd1834de2750b47fb6d192c6f6Timo Sirainen if ((sync_flags & MAILDIR_UIDLIST_SYNC_KEEP_STATE) == 0) {
8925c5450daddcdd1834de2750b47fb6d192c6f6Timo Sirainen /* initially mark all nonsynced */
8925c5450daddcdd1834de2750b47fb6d192c6f6Timo Sirainen maildir_uidlist_mark_all(uidlist, TRUE);
8925c5450daddcdd1834de2750b47fb6d192c6f6Timo Sirainen }
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen return 1;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen }
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen i_assert(uidlist->locked_refresh);
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
588f592a98fca95a10aaccdc76a589558e9ba125Timo Sirainen ctx->record_pool = pool_alloconly_create(MEMPOOL_GROWING
588f592a98fca95a10aaccdc76a589558e9ba125Timo Sirainen "maildir_uidlist_sync", 16384);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&ctx->files, ctx->record_pool, 4096,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen maildir_filename_base_hash,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen maildir_filename_base_cmp);
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen i_array_init(&ctx->records, array_count(&uidlist->records));
57a91f930a12d2cd1220da4f3f7cb2c47557cd37Timo Sirainen return 1;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainenstatic int
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainenmaildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen const char *filename, uint32_t uid,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen enum maildir_uidlist_rec_flag flags,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen struct maildir_uidlist_rec **rec_r)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen struct maildir_uidlist *uidlist = ctx->uidlist;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen struct maildir_uidlist_rec *rec, *const *recs;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen unsigned int count;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen /* we'll update uidlist directly */
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(uidlist->files, filename);
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen if (rec == NULL) {
746a7ec64a09649ed3c96c88b97cdc370a7bbe2fTimo Sirainen /* doesn't exist in uidlist */
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (!ctx->locked) {
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen /* we can't add it, so just ignore it */
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen return 1;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (ctx->first_new_pos == UINT_MAX)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen ctx->first_new_pos = array_count(&uidlist->records);
38da5c23b0a8b4012e79fcf647a8749786c83c51Timo Sirainen ctx->new_files_count++;
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen ctx->changed = TRUE;
edf8c636e80ad4cfe5dd29525c718898685fc2c3Timo Sirainen
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen if (uidlist->record_pool == NULL) {
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen uidlist->record_pool =
588f592a98fca95a10aaccdc76a589558e9ba125Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING
588f592a98fca95a10aaccdc76a589558e9ba125Timo Sirainen "uidlist record_pool",
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen 1024);
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen }
92888ef30960c30ccc9e030fe7eab5d4d04a7d1cTimo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen rec = p_new(uidlist->record_pool,
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen struct maildir_uidlist_rec, 1);
38da5c23b0a8b4012e79fcf647a8749786c83c51Timo Sirainen rec->uid = (uint32_t)-1;
042668c0cd5a7d35ce6373ae493695e8f12d3157Timo Sirainen rec->filename = p_strdup(uidlist->record_pool, filename);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen array_append(&uidlist->records, &rec, 1);
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen uidlist->change_counter++;
042668c0cd5a7d35ce6373ae493695e8f12d3157Timo Sirainen
042668c0cd5a7d35ce6373ae493695e8f12d3157Timo Sirainen hash_table_insert(uidlist->files, rec->filename, rec);
38920bff33eaa2acef5c200df5ce7088fd61e673Timo Sirainen } else if (strcmp(rec->filename, filename) != 0) {
38920bff33eaa2acef5c200df5ce7088fd61e673Timo Sirainen rec->filename = p_strdup(uidlist->record_pool, filename);
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen }
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if (uid != 0) {
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen if (rec->uid != uid && rec->uid != (uint32_t)-1) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(uidlist->box,
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen "Maildir: %s changed UID %u -> %u",
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen filename, rec->uid, uid);
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen return -1;
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen }
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen rec->uid = uid;
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if (uidlist->next_uid <= uid)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen uidlist->next_uid = uid + 1;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen else {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen recs = array_get(&uidlist->records, &count);
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen if (count > 1 && uid < recs[count-1]->uid)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen uidlist->unsorted = TRUE;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen }
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen }
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
51335acfa1580c6f6b1aa1bdb915d2cb5e0e67a4Timo Sirainen rec->flags &= ~MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
f6b317c4a91d72d5e0dcd14940ae023233845aa0Timo Sirainen rec->flags = (rec->flags | flags) &
51335acfa1580c6f6b1aa1bdb915d2cb5e0e67a4Timo Sirainen ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainen
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainen ctx->finished = FALSE;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen *rec_r = rec;
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainenstatic unsigned char *ext_dup(pool_t pool, const unsigned char *extensions)
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen{
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen unsigned char *ret;
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen if (extensions == NULL)
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen return NULL;
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen unsigned int len;
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen for (len = 0; extensions[len] != '\0'; len++) {
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen while (extensions[len] != '\0') len++;
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen }
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen ret = p_malloc(pool, len + 1);
1930b9fae508a90de5f08fcd74602cbe3a5a5964Timo Sirainen memcpy(ret, extensions, len);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen return ret;
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen}
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen const char *filename,
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen enum maildir_uidlist_rec_flag flags)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen{
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen struct maildir_uidlist_rec *rec;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen return maildir_uidlist_sync_next_uid(ctx, filename, 0, flags, &rec);
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen}
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainenint maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen const char *filename, uint32_t uid,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen enum maildir_uidlist_rec_flag flags,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen struct maildir_uidlist_rec **rec_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
edf8c636e80ad4cfe5dd29525c718898685fc2c3Timo Sirainen struct maildir_uidlist *uidlist = ctx->uidlist;
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen struct maildir_uidlist_rec *rec, *old_rec;
feaa6a3d82ea61496ced1f83a726ff33047c7da2Timo Sirainen const char *p;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen *rec_r = NULL;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->failed)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen for (p = filename; *p != '\0'; p++) {
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen if (*p == 13 || *p == 10) {
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen i_warning("Maildir %s: Ignoring a file with #0x%x: %s",
feaa6a3d82ea61496ced1f83a726ff33047c7da2Timo Sirainen mailbox_get_path(uidlist->box), *p, filename);
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen return 1;
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen }
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen }
32147ee6bdea566e64139b77ad0ea89960200df9Timo Sirainen
f07762518db1e3771500a1a761ea0c06be23b8b5Timo Sirainen if (ctx->partial) {
056bbae2011f2d93570e59c0618702d835d7e244Timo Sirainen return maildir_uidlist_sync_next_partial(ctx, filename,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen uid, flags, rec_r);
f07762518db1e3771500a1a761ea0c06be23b8b5Timo Sirainen }
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(ctx->files, filename);
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen if (rec != NULL) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if ((rec->flags & (MAILDIR_UIDLIST_REC_FLAG_NEW_DIR |
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen MAILDIR_UIDLIST_REC_FLAG_MOVED)) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* possibly duplicate */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* probably was in new/ and now we're seeing it in cur/.
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen remove new/moved flags so if this happens again we'll know
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen to check for duplicates. */
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen rec->flags &= ~(MAILDIR_UIDLIST_REC_FLAG_NEW_DIR |
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen MAILDIR_UIDLIST_REC_FLAG_MOVED);
38920bff33eaa2acef5c200df5ce7088fd61e673Timo Sirainen if (strcmp(rec->filename, filename) != 0)
38920bff33eaa2acef5c200df5ce7088fd61e673Timo Sirainen rec->filename = p_strdup(ctx->record_pool, filename);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen old_rec = hash_table_lookup(uidlist->files, filename);
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen i_assert(old_rec != NULL || UIDLIST_IS_LOCKED(uidlist));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen rec = p_new(ctx->record_pool, struct maildir_uidlist_rec, 1);
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen
be6a511e672b84b1622f1875b2527827e20cbcb4Timo Sirainen if (old_rec != NULL) {
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen *rec = *old_rec;
be6a511e672b84b1622f1875b2527827e20cbcb4Timo Sirainen rec->extensions =
8e1c66e6f43698fbd5ae8b00863cbe10581aa9fdTimo Sirainen ext_dup(ctx->record_pool, rec->extensions);
be6a511e672b84b1622f1875b2527827e20cbcb4Timo Sirainen } else {
38da5c23b0a8b4012e79fcf647a8749786c83c51Timo Sirainen rec->uid = (uint32_t)-1;
38da5c23b0a8b4012e79fcf647a8749786c83c51Timo Sirainen ctx->new_files_count++;
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen ctx->changed = TRUE;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen /* didn't exist in uidlist, it's recent */
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen flags |= MAILDIR_UIDLIST_REC_FLAG_RECENT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
042668c0cd5a7d35ce6373ae493695e8f12d3157Timo Sirainen rec->filename = p_strdup(ctx->record_pool, filename);
042668c0cd5a7d35ce6373ae493695e8f12d3157Timo Sirainen hash_table_insert(ctx->files, rec->filename, rec);
57a181d2ecd59039a4fc5c6bf0af72a7cd6a051fTimo Sirainen
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen array_append(&ctx->records, &rec, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if (uid != 0) {
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen rec->uid = uid;
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if (uidlist->next_uid <= uid)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen uidlist->next_uid = uid + 1;
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
054fdbfc20f57cb4a386e088ec773d9980ac8b2cTimo Sirainen rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen *rec_r = rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainenvoid maildir_uidlist_sync_remove(struct maildir_uidlist_sync_ctx *ctx,
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen const char *filename)
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen{
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen struct maildir_uidlist_rec *rec;
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen unsigned int idx;
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen i_assert(ctx->partial);
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen i_assert(ctx->uidlist->locked_refresh);
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(ctx->uidlist->files, filename);
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen i_assert(rec != NULL);
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen i_assert(rec->uid != (uint32_t)-1);
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_remove(ctx->uidlist->files, filename);
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen idx = maildir_uidlist_records_array_delete(ctx->uidlist, rec);
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (ctx->first_unwritten_pos != UINT_MAX) {
dc40ce1dda503f114e9505c2da9371fd3cb34096Timo Sirainen i_assert(ctx->first_unwritten_pos > idx);
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen ctx->first_unwritten_pos--;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (ctx->first_new_pos != UINT_MAX) {
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen i_assert(ctx->first_new_pos > idx);
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen ctx->first_new_pos--;
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen }
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen ctx->changed = TRUE;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen ctx->uidlist->recreate = TRUE;
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen}
2087637d10ad94ea029fe055f8ee55cd594955a8Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainenvoid maildir_uidlist_sync_set_ext(struct maildir_uidlist_sync_ctx *ctx,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen struct maildir_uidlist_rec *rec,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen enum maildir_uidlist_rec_ext_key key,
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen const char *value)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen{
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen pool_t pool = ctx->partial ?
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen ctx->uidlist->record_pool : ctx->record_pool;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen i_assert(MAILDIR_UIDLIST_REC_EXT_KEY_IS_VALID(key));
ac1c79d03888e634d26914780f7a7bc9cf3bd4b6Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen maildir_uidlist_rec_set_ext(rec, pool, key, value);
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen}
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainenconst char *
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainenmaildir_uidlist_sync_get_full_filename(struct maildir_uidlist_sync_ctx *ctx,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen const char *filename)
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen{
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct maildir_uidlist_rec *rec;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(ctx->files, filename);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen return rec == NULL ? NULL : rec->filename;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen}
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainenbool maildir_uidlist_get_uid(struct maildir_uidlist *uidlist,
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen const char *filename, uint32_t *uid_r)
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen{
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen struct maildir_uidlist_rec *rec;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(uidlist->files, filename);
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen if (rec == NULL)
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen return FALSE;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen *uid_r = rec->uid;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen return TRUE;
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen}
228edfb38d7f1a0bfe36f74e7c521006ea48fbdfTimo Sirainen
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainenvoid maildir_uidlist_update_fname(struct maildir_uidlist *uidlist,
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen const char *filename)
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen{
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen struct maildir_uidlist_rec *rec;
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen rec = hash_table_lookup(uidlist->files, filename);
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen if (rec == NULL)
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen return;
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen rec->flags &= ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen if (strcmp(rec->filename, filename) != 0)
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen rec->filename = p_strdup(uidlist->record_pool, filename);
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen}
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainenconst char *
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainenmaildir_uidlist_get_full_filename(struct maildir_uidlist *uidlist,
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen const char *filename)
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen{
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen struct maildir_uidlist_rec *rec;
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(uidlist->files, filename);
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen return rec == NULL ? NULL : rec->filename;
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen}
0f506139b4c95589a09a81a5d51636aee994cd1eTimo Sirainen
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainenstatic int maildir_assign_uid_cmp(const void *p1, const void *p2)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if ((*rec1)->uid != (*rec2)->uid) {
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if ((*rec1)->uid < (*rec2)->uid)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen return -1;
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen else
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen return 1;
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen }
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen return maildir_filename_sort_cmp((*rec1)->filename, (*rec2)->filename);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainenstatic void maildir_uidlist_assign_uids(struct maildir_uidlist_sync_ctx *ctx)
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen{
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen struct maildir_uidlist_rec **recs;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen unsigned int dest, count;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen i_assert(UIDLIST_IS_LOCKED(ctx->uidlist));
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen i_assert(ctx->first_new_pos != UINT_MAX);
b06bfeaa9bb367b72edd51672c33e24d33d8ff1bTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (ctx->first_unwritten_pos == UINT_MAX)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen ctx->first_unwritten_pos = ctx->first_new_pos;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen /* sort new files and assign UIDs for them */
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen recs = array_get_modifiable(&ctx->uidlist->records, &count);
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen qsort(recs + ctx->first_new_pos, count - ctx->first_new_pos,
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen sizeof(*recs), maildir_assign_uid_cmp);
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen for (dest = ctx->first_new_pos; dest < count; dest++) {
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen if (recs[dest]->uid == (uint32_t)-1)
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen break;
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen }
12e145323c63ecf3d3522bf1381012a985caa844Timo Sirainen
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen for (; dest < count; dest++) {
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen i_assert(recs[dest]->uid == (uint32_t)-1);
ebc973d8a29738c9b91e5c92a124375661df799bTimo Sirainen i_assert(ctx->uidlist->next_uid < (uint32_t)-1);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen recs[dest]->uid = ctx->uidlist->next_uid++;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen recs[dest]->flags &= ~MAILDIR_UIDLIST_REC_FLAG_MOVED;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen }
de83e0a4081e68172b66dd7fa9788effacdc1448Timo Sirainen
f53a6e86c03f51ca7fb23a03751dfc88aa2d32f0Timo Sirainen if (ctx->uidlist->locked_refresh && ctx->uidlist->initial_read)
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen ctx->uidlist->last_seen_uid = ctx->uidlist->next_uid-1;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainen ctx->new_files_count = 0;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ctx->first_new_pos = UINT_MAX;
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainen ctx->uidlist->change_counter++;
bb592fc58fe5c3e81ad941637fbb30d1d1cd8694Timo Sirainen ctx->finish_change_counter = ctx->uidlist->change_counter;
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen}
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void maildir_uidlist_swap(struct maildir_uidlist_sync_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist *uidlist = ctx->uidlist;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b06bfeaa9bb367b72edd51672c33e24d33d8ff1bTimo Sirainen /* buffer is unsorted, sort it by UID */
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen array_sort(&ctx->records, maildir_uid_cmp);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen array_free(&uidlist->records);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen uidlist->records = ctx->records;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen ctx->records.arr.buffer = NULL;
8409959d66804dc963bc6fcdcc9a01da0d56a978Timo Sirainen i_assert(array_is_created(&uidlist->records));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&uidlist->files);
3a282e21c69b9cad1b5f9359ec3aebd3c8b8e901Timo Sirainen uidlist->files = ctx->files;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx->files);
3a282e21c69b9cad1b5f9359ec3aebd3c8b8e901Timo Sirainen
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&uidlist->record_pool);
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen uidlist->record_pool = ctx->record_pool;
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen ctx->record_pool = NULL;
033557e1c8ebec5ae31f2f24fab90226a1945168Timo Sirainen
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen if (ctx->new_files_count != 0) {
3054cbf69a94ca08123ca3a8d6a2c19a1784e11dTimo Sirainen ctx->first_new_pos = array_count(&uidlist->records) -
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen ctx->new_files_count;
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainen maildir_uidlist_assign_uids(ctx);
bb592fc58fe5c3e81ad941637fbb30d1d1cd8694Timo Sirainen } else {
bb592fc58fe5c3e81ad941637fbb30d1d1cd8694Timo Sirainen ctx->uidlist->change_counter++;
d5bae4060a1ba3fe663991169de7102f81039304Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainenvoid maildir_uidlist_sync_recreate(struct maildir_uidlist_sync_ctx *ctx)
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen{
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen ctx->uidlist->recreate = TRUE;
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen}
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen
73c76fa7340a107229c530196d026aadeae979c7Timo Sirainenvoid maildir_uidlist_sync_finish(struct maildir_uidlist_sync_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (!ctx->partial) {
73c76fa7340a107229c530196d026aadeae979c7Timo Sirainen if (!ctx->failed)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen maildir_uidlist_swap(ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (ctx->new_files_count != 0 && !ctx->failed) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen i_assert(ctx->changed);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen i_assert(ctx->locked);
bef19e231b696a2018fcb93d546a41fcf732c243Timo Sirainen maildir_uidlist_assign_uids(ctx);
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b06bfeaa9bb367b72edd51672c33e24d33d8ff1bTimo Sirainen
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen ctx->finished = TRUE;
82037d2bd997fef300025391353da4e085de9b4cTimo Sirainen
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen /* mbox=NULL means we're coming from dbox rebuilding code.
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen the dbox is already locked, so allow uidlist recreation */
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen i_assert(ctx->locked || !ctx->changed);
da8115ebacf055f87ec71ae1155a421452f2e0d5Timo Sirainen if ((ctx->changed || maildir_uidlist_want_compress(ctx)) &&
d656ea23231ca1232b2dae327cea83bb44c6f6ffTimo Sirainen !ctx->failed && ctx->locked) {
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen T_BEGIN {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (maildir_uidlist_sync_update(ctx) < 0) {
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen /* we couldn't write everything we wanted. make
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen sure we don't continue using those UIDs */
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen maildir_uidlist_reset(ctx->uidlist);
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen ctx->failed = TRUE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen }
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen } T_END;
777ff25e82e0305e2696bcbe3c6e0274e3e8ce10Timo Sirainen }
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen}
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainenint maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx **_ctx,
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen bool success)
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen{
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen struct maildir_uidlist_sync_ctx *ctx = *_ctx;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen int ret;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen *_ctx = NULL;
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (!success)
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen ctx->failed = TRUE;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen ret = ctx->failed ? -1 : 0;
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen if (!ctx->finished)
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen maildir_uidlist_sync_finish(ctx);
5375aa138868dc2c45eb1a4ff37a0b577c2814f8Timo Sirainen if (ctx->partial)
5375aa138868dc2c45eb1a4ff37a0b577c2814f8Timo Sirainen maildir_uidlist_mark_all(ctx->uidlist, FALSE);
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (ctx->locked)
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen maildir_uidlist_unlock(ctx->uidlist);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen if (hash_table_is_created(ctx->files))
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&ctx->files);
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&ctx->record_pool);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen if (array_is_created(&ctx->records))
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen array_free(&ctx->records);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainenvoid maildir_uidlist_add_flags(struct maildir_uidlist *uidlist,
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen const char *filename,
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen enum maildir_uidlist_rec_flag flags)
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen{
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen struct maildir_uidlist_rec *rec;
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen rec = hash_table_lookup(uidlist->files, filename);
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen i_assert(rec != NULL);
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen rec->flags |= flags;
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen}
316689d0ef55e2fa4e2fb4ac5b1ea35ce65688d3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct maildir_uidlist_iter_ctx *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaildir_uidlist_iter_init(struct maildir_uidlist *uidlist)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist_iter_ctx *ctx;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen unsigned int count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct maildir_uidlist_iter_ctx, 1);
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen ctx->uidlist = uidlist;
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen ctx->next = array_get(&uidlist->records, &count);
43f6755bda8c834bf7a7120e6b485c35e27ee8bdTimo Sirainen ctx->end = ctx->next + count;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen ctx->change_counter = ctx->uidlist->change_counter;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainenstatic void
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainenmaildir_uidlist_iter_update_idx(struct maildir_uidlist_iter_ctx *ctx)
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen{
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen unsigned int old_rev_idx, idx, count;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen old_rev_idx = ctx->end - ctx->next;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen ctx->next = array_get(&ctx->uidlist->records, &count);
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen ctx->end = ctx->next + count;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen idx = old_rev_idx >= count ? 0 :
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen count - old_rev_idx;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen while (idx < count && ctx->next[idx]->uid <= ctx->prev_uid)
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen idx++;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen while (idx > 0 && ctx->next[idx-1]->uid > ctx->prev_uid)
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen idx--;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen ctx->next += idx;
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen}
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenstatic bool maildir_uidlist_iter_next_rec(struct maildir_uidlist_iter_ctx *ctx,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen struct maildir_uidlist_rec **rec_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen struct maildir_uidlist_rec *rec;
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen if (ctx->change_counter != ctx->uidlist->change_counter)
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen maildir_uidlist_iter_update_idx(ctx);
dc4e0821e709d93c8504e50b4ba0aaeb5ce9e032Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->next == ctx->end)
1302f472805684b42ead4be8e4d5cbd95dfdc29bTimo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen rec = *ctx->next;
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen i_assert(rec->uid != (uint32_t)-1);
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen ctx->prev_uid = rec->uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->next++;
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen *rec_r = rec;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return TRUE;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen}
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainenbool maildir_uidlist_iter_next(struct maildir_uidlist_iter_ctx *ctx,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen uint32_t *uid_r,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen enum maildir_uidlist_rec_flag *flags_r,
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen const char **filename_r)
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen{
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen struct maildir_uidlist_rec *rec;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen if (!maildir_uidlist_iter_next_rec(ctx, &rec))
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen return FALSE;
621e8c0767de486db8d4ebb317d441b3f3a0434fTimo Sirainen
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen *uid_r = rec->uid;
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen *flags_r = rec->flags;
6681a083b7e8c552d3a6bccb32bbbdb7e7987bf6Timo Sirainen *filename_r = rec->filename;
1302f472805684b42ead4be8e4d5cbd95dfdc29bTimo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainenvoid maildir_uidlist_iter_deinit(struct maildir_uidlist_iter_ctx **_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen i_free(*_ctx);
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen *_ctx = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}