maildir-sync.c revision 814565216099ac2b40c2862013d092d2f575802a
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2002-2003 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "buffer.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "hash.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "maildir-index.h"
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen#include "maildir-uidlist.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-data.h"
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include "mail-index-util.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen#include <fcntl.h>
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen#include <dirent.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <utime.h>
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenenum maildir_file_action {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAILDIR_FILE_ACTION_EXPUNGE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAILDIR_FILE_ACTION_UPDATE_FLAGS,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen MAILDIR_FILE_ACTION_UPDATE_CONTENT,
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen MAILDIR_FILE_ACTION_NEW,
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen MAILDIR_FILE_ACTION_NONE
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct maildir_hash_context {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index *index;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_record *new_mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int failed;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainenstruct maildir_hash_rec {
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen struct mail_index_record *rec;
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen enum maildir_file_action action;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen};
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainenstatic int maildir_update_filename(struct mail_index *index,
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen struct mail_index_record *rec,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen const char *new_fname)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_update *update;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen update = index->update_begin(index, rec);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen return index->update_end(update);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int maildir_update_flags(struct mail_index *index,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_record *rec,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int seq, const char *new_fname)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mail_flags flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen flags = maildir_filename_get_flags(new_fname, rec->msg_flags);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (flags != rec->msg_flags) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (!index->update_flags(index, rec, seq, flags, TRUE))
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return FALSE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return TRUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
ba00293b85c7fb4e7a2d100991c716e17b9daaaeTimo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainenstatic int is_file_content_changed(struct mail_index *index,
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen struct mail_index_record *rec,
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen const char *dir, const char *fname)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#define DATA_HDR_SIZE (DATA_HDR_HEADER_SIZE | DATA_HDR_BODY_SIZE)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen struct mail_index_data_record_header *data_hdr;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *path;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->data_fields & DATA_HDR_INTERNAL_DATE) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (rec->data_fields & DATA_HDR_SIZE) != DATA_HDR_SIZE) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* nothing in cache, we can't know if it's changed */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen t_push();
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen path = t_strdup_printf("%s/%s", dir, fname);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (stat(path, &st) < 0) {
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (errno != ENOENT)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen index_file_set_syscall_error(index, path, "stat()");
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen t_pop();
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return FALSE;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen }
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen t_pop();
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen data_hdr = mail_index_data_lookup_header(index->data, rec);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (data_hdr == NULL)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return FALSE;
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen if ((rec->data_fields & DATA_HDR_INTERNAL_DATE) != 0 &&
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen st.st_mtime != data_hdr->internal_date)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return TRUE;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if ((rec->data_fields & DATA_HDR_SIZE) == DATA_HDR_SIZE &&
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen (uoff_t)st.st_size != data_hdr->body_size + data_hdr->header_size)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return TRUE;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return FALSE;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen}
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen/* a char* hash function from ASU -- from glib */
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstatic unsigned int maildir_hash(const void *p)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen const unsigned char *s = p;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen unsigned int g, h = 0;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen while (*s != ':' && *s != '\0') {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen h = (h << 4) + *s;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((g = h & 0xf0000000UL)) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen h = h ^ (g >> 24);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen h = h ^ g;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen }
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen s++;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return h;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainenstatic int maildir_cmp(const void *p1, const void *p2)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen const char *s1 = p1, *s2 = p2;
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen while (*s1 == *s2 && *s1 != ':' && *s1 != '\0') {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen s1++; s2++;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if ((*s1 == '\0' || *s1 == ':') &&
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen (*s2 == '\0' || *s2 == '\0'))
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return 0;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return *s1 - *s2;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainenstatic void uidlist_hash_get_filenames(void *key, void *value, void *context)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen buffer_t *buf = context;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct maildir_hash_rec *hash_rec = value;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (hash_rec->action == MAILDIR_FILE_ACTION_NEW)
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen buffer_append(buf, (const void *) &key, sizeof(key));
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstatic int maildir_sync_uidlist(struct mail_index *index, const char *dir,
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen struct maildir_uidlist *uidlist,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen struct hash_table *files, pool_t pool,
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen unsigned int new_count)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen struct mail_index_record *rec;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen struct maildir_hash_rec *hash_rec;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct maildir_uidlist_rec uid_rec;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen const char *fname, **new_files;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen void *orig_key, *orig_value;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen unsigned int seq, uid, last_uid, i;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen buffer_t *buf;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen seq = 0;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen rec = index->lookup(index, 1);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (uidlist == NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen memset(&uid_rec, 0, sizeof(uid_rec));
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen else {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return FALSE;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen }
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen while (rec != NULL) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen seq++; uid = rec->uid;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen /* skip over the expunged records in uidlist */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen while (uid_rec.uid != 0 && uid_rec.uid < uid) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen uidlist->rewrite = TRUE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (!maildir_uidlist_next(uidlist, &uid_rec))
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return FALSE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen fname = maildir_get_location(index, rec);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (fname == NULL) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen hash_destroy(files);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return FALSE;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen hash_rec = hash_lookup(files, fname);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (hash_rec == NULL) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen index_set_corrupted(index, "Unexpectedly lost file "
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen "%s from hash", fname);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen return FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (uid_rec.uid == uid &&
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen maildir_cmp(fname, uid_rec.filename) != 0) {
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen index_set_corrupted(index, "Filename mismatch for UID "
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen "%u: %s vs %s", uid, fname,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uid_rec.filename);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (uid_rec.uid > uid &&
6825360d446542046757b06064282301c4c6b27cTimo Sirainen (hash_rec->action == MAILDIR_FILE_ACTION_UPDATE_FLAGS ||
6825360d446542046757b06064282301c4c6b27cTimo Sirainen hash_rec->action == MAILDIR_FILE_ACTION_NONE)) {
6825360d446542046757b06064282301c4c6b27cTimo Sirainen /* it's UID has changed */
6825360d446542046757b06064282301c4c6b27cTimo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_UPDATE_CONTENT;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen /* make sure filename is not invalidated by expunge */
6825360d446542046757b06064282301c4c6b27cTimo Sirainen hash_insert(files, p_strdup(pool, fname), hash_rec);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen }
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen switch (hash_rec->action) {
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen case MAILDIR_FILE_ACTION_EXPUNGE:
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen if (!index->expunge(index, rec, seq, TRUE))
6825360d446542046757b06064282301c4c6b27cTimo Sirainen return FALSE;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen seq--;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAILDIR_FILE_ACTION_UPDATE_FLAGS:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!maildir_update_flags(index, rec, seq, fname))
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen break;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen case MAILDIR_FILE_ACTION_UPDATE_CONTENT:
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (!index->expunge(index, rec, seq, TRUE))
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return FALSE;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen seq--;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_NEW;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen new_count++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen break;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen case MAILDIR_FILE_ACTION_NONE:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen break;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen default:
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_unreached();
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (uid_rec.uid == uid) {
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return FALSE;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen rec = index->next(index, rec);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (seq != index->header->messages_count) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen index_set_corrupted(index, "Wrong messages_count in header "
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen "(%u != %u)", seq,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen index->header->messages_count);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return FALSE;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* if there's mails with UIDs in uidlist, write them */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen last_uid = 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen while (uid_rec.uid != 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!hash_lookup_full(files, uid_rec.filename,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen &orig_key, &orig_value)) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* expunged */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (uidlist != NULL)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen uidlist->rewrite = TRUE;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen } else {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen hash_rec = orig_value;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen i_assert(hash_rec->action == MAILDIR_FILE_ACTION_NEW);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen /* make sure we set the same UID for it. */
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (index->header->next_uid > uid_rec.uid) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen index_set_corrupted(index,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen "index.next_uid (%u) > "
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen "uid_rec.uid (%u)",
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen index->header->next_uid,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen uid_rec.uid);
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen return FALSE;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen }
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen index->header->next_uid = uid_rec.uid;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_NONE;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen new_count--;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (!maildir_index_append_file(index, dir, orig_key))
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen if (maildir_uidlist_next(uidlist, &uid_rec) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (new_count == 0 || !INDEX_IS_UIDLIST_LOCKED(index)) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen /* all done (or can't do it since we don't have lock) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen if (uidlist != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uidlist->rewrite = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* then there's the completely new mails. sort them by the filename
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen so we should get them to same order as they were created. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buf = buffer_create_static_hard(pool, new_count * sizeof(const char *));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hash_foreach(files, uidlist_hash_get_filenames, buf);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(buffer_get_used_size(buf) / sizeof(const char *) <= new_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_files = buffer_get_modifyable_data(buf, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen qsort(new_files, new_count, sizeof(const char *),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (int (*)(const void *, const void *)) strcmp);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* and finally write */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < new_count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!maildir_index_append_file(index, dir, new_files[i]))
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenstatic int maildir_index_sync_dir(struct mail_index *index, const char *dir,
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen struct maildir_uidlist *uidlist)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen{
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen pool_t pool;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen struct hash_table *files;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen struct mail_index_record *rec;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen struct maildir_hash_rec *hash_rec;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen DIR *dirp;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen struct dirent *d;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen const char *fname;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen void *orig_key, *orig_value;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen unsigned int new_count;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen size_t size;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int failed, check_content_changes;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen i_assert(dir != NULL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (index->header->messages_count >= INT_MAX/32) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index_set_corrupted(index, "Header says %u messages",
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen index->header->messages_count);
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen return FALSE;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen }
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen /* read current messages in index into hash */
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen size = nearest_power(index->header->messages_count *
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen sizeof(struct maildir_hash_rec) + 1024);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen pool = pool_alloconly_create("maildir sync", I_MAX(size, 16384));
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen files = hash_create(default_pool, pool, index->header->messages_count*2,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen maildir_hash, maildir_cmp);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen rec = index->lookup(index, 1);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen while (rec != NULL) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen fname = maildir_get_location(index, rec);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (fname == NULL) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_destroy(files);
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen return FALSE;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen }
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen hash_rec = p_new(pool, struct maildir_hash_rec, 1);
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen hash_rec->rec = rec;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_EXPUNGE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hash_insert(files, (void *) fname, hash_rec);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen rec = index->next(index, rec);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* Do we want to check changes in file contents? This slows down
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen things as we need to do extra stat() for all files. */
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen check_content_changes = getenv("MAILDIR_CHECK_CONTENT_CHANGES") != NULL;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen dirp = opendir(dir);
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (dirp == NULL)
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen return index_file_set_syscall_error(index, dir, "opendir()");
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen new_count = 0; failed = FALSE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen while ((d = readdir(dirp)) != NULL) {
99e8698f598d2b83da7c581584a538c0713fd11dTimo Sirainen if (d->d_name[0] == '.')
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen continue;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!hash_lookup_full(files, d->d_name,
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen &orig_key, &orig_value)) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen hash_rec = p_new(pool, struct maildir_hash_rec, 1);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen } else {
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen hash_rec = orig_value;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (hash_rec->action != MAILDIR_FILE_ACTION_EXPUNGE) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* FIXME: duplicate */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen continue;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (hash_rec->rec == NULL) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* new message */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen new_count++;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_NEW;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_insert(files, p_strdup(pool, d->d_name), hash_rec);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen } else if (check_content_changes &&
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen is_file_content_changed(index, rec,
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen dir, d->d_name)) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* file content changed, treat it as new message */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_UPDATE_CONTENT;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* make sure filename is not invalidated by expunge
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen later. the file name may have changed also. */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_insert(files, p_strdup(pool, d->d_name), hash_rec);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen } else if (strcmp(orig_key, d->d_name) != 0) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* update filename now, flags later */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_UPDATE_FLAGS;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (!maildir_update_filename(index, hash_rec->rec,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen d->d_name)) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen failed = TRUE;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen } else {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hash_rec->action = MAILDIR_FILE_ACTION_NONE;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainen if (closedir(dirp) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_file_set_syscall_error(index, dir, "closedir()");
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (!failed) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen failed = !maildir_sync_uidlist(index, dir, uidlist,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen files, pool, new_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hash_destroy(files);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pool_unref(pool);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return !failed;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen
e670e1783fe4541dc3fc6109a181d45b0a9c2635Timo Sirainenstatic int maildir_new_scan_first_file(struct mail_index *index,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen const char *dir, DIR **dirp,
e670e1783fe4541dc3fc6109a181d45b0a9c2635Timo Sirainen struct dirent **d)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen *dirp = opendir(dir);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (*dirp == NULL)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return index_file_set_syscall_error(index, dir, "opendir()");
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen /* find first file */
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen while ((*d = readdir(*dirp)) != NULL) {
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen if ((*d)->d_name[0] != '.')
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen if (*d == NULL) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (closedir(*dirp) < 0)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen index_file_set_syscall_error(index, dir, "closedir()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *dirp = NULL;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return TRUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenstatic int maildir_index_lock_and_sync(struct mail_index *index, int *changes,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen DIR *new_dirp, struct dirent *new_dent,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct maildir_uidlist **uidlist_r)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct stat st, std;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct utimbuf ut;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct maildir_uidlist *uidlist;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const char *uidlist_path, *cur_dir, *new_dir;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen time_t index_mtime, uidlist_mtime;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int cur_changed;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *uidlist_r = uidlist = NULL;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (index->fd == -1) {
eb77c0a041648af50abc027811f6b7951c3a80cdTimo Sirainen /* anon-mmaped */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index_mtime = index->file_sync_stamp;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen } else {
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen if (fstat(index->fd, &st) < 0)
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen return index_set_syscall_error(index, "fstat()");
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen index_mtime = st.st_mtime;
6143fece58262865ce89b5012b73ef08f2ad6abcTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cur_dir = t_strconcat(index->mailbox_path, "/cur", NULL);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (stat(cur_dir, &std) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return index_file_set_syscall_error(index, cur_dir, "stat()");
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen uidlist_path = t_strconcat(index->mailbox_path,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "/" MAILDIR_UIDLIST_NAME, NULL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (stat(uidlist_path, &st) < 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (errno != ENOENT) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return index_file_set_syscall_error(index, uidlist_path,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "stat()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen memset(&st, 0, sizeof(st));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cur_changed = TRUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uidlist_mtime = 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen } else {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* FIXME: save mtime into index header, so we don't
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen have to read it every time mailbox is opened */
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen uidlist_mtime = st.st_mtime;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen cur_changed = index_mtime != std.st_mtime ||
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen index->uidlist_mtime != uidlist_mtime;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (new_dirp != NULL || cur_changed) {
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen if (maildir_uidlist_try_lock(index) < 0)
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen return FALSE;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen /* we may or may not have succeeded. if we didn't,
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen just continue by syncing with existing uidlist file */
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen if (!cur_changed && !INDEX_IS_UIDLIST_LOCKED(index)) {
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen /* just new mails in new/ dir, we can't sync them
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen if we can't get the lock. */
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *uidlist_r = uidlist = maildir_uidlist_open(index);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uidlist != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uidlist->uid_validity != index->header->uid_validity) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* uidvalidity changed */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!index->rebuilding && index->opened) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_set_corrupted(index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "UIDVALIDITY changed in uidlist");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!index->rebuilding) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->set_flags |= MAIL_INDEX_FLAG_REBUILD;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->header->uid_validity = uidlist->uid_validity;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(index->header->next_uid == 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen if (uidlist != NULL &&
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen index->header->next_uid > uidlist->next_uid) {
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen index_set_corrupted(index, "index.next_uid (%u) > "
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen "uidlist.next_uid (%u)",
c61d52810496376a2ea60b8f4e27bbcaa8754f3fTimo Sirainen index->header->next_uid,
2469ed8e17534f6cb5f41493df8c7e6f3b2c9b61Timo Sirainen uidlist->next_uid);
c61d52810496376a2ea60b8f4e27bbcaa8754f3fTimo Sirainen return FALSE;
f4e0148e539c6dd4e12b8305ab0dd5e63c46ba67Timo Sirainen }
f4e0148e539c6dd4e12b8305ab0dd5e63c46ba67Timo Sirainen
f4e0148e539c6dd4e12b8305ab0dd5e63c46ba67Timo Sirainen if (changes != NULL)
2bd96c58be42146cb84076331604cadb2994fce5Timo Sirainen *changes = TRUE;
2bd96c58be42146cb84076331604cadb2994fce5Timo Sirainen }
2bd96c58be42146cb84076331604cadb2994fce5Timo Sirainen
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen /* move mail from new/ to cur/ */
27db4ce5fe399c981e09dcf9e885a1546afd34f4Timo Sirainen if (new_dirp != NULL && INDEX_IS_UIDLIST_LOCKED(index)) {
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen new_dir = t_strconcat(index->mailbox_path, "/new", NULL);
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen if (!maildir_index_build_dir(index, new_dir, cur_dir,
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen new_dirp, new_dent))
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen return FALSE;
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen if (uidlist != NULL)
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen uidlist->rewrite = TRUE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen /* set cur/ directory's timestamp into past to make sure we
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen notice if new mail is moved there */
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen ut.actime = ut.modtime = ioloop_time-60;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen if (utime(cur_dir, &ut) < 0) {
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen index_file_set_syscall_error(index, cur_dir, "utime()");
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen return FALSE;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen }
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen /* We have to always scan the cur/ directory to make
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen sure we don't miss any mails some other non-Dovecot
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen client may have moved there. FIXME: make it
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen optional, it's unnecessary with Dovecot-only setup */
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen cur_changed = TRUE;
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen /* set the cur/ directory's timestamp */
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen std.st_mtime = ut.modtime;
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen }
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen if (cur_changed) {
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen if (!maildir_index_sync_dir(index, cur_dir, uidlist))
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen return FALSE;
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen }
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen if (uidlist != NULL && uidlist->next_uid > index->header->next_uid)
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen index->header->next_uid = uidlist->next_uid;
bc1d1497d715cc5c820ff518f070f78c39ef6cdcTimo Sirainen
bc1d1497d715cc5c820ff518f070f78c39ef6cdcTimo Sirainen if ((new_dirp != NULL || cur_changed) &&
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen (uidlist == NULL || uidlist->rewrite)) {
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen if (!INDEX_IS_UIDLIST_LOCKED(index)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* there's more new mails, but we need .lock file to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen be able to sync them. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!maildir_uidlist_rewrite(index, &uidlist_mtime))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* uidlist file synced */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->uidlist_mtime = uidlist_mtime;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* update sync stamp */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->file_sync_stamp = std.st_mtime;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (index->lock_type == MAIL_LOCK_UNLOCK && !index->anon_mmap) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* no changes to index, we need to update it's timestamp
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ourself to get it changed */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ut.actime = ioloop_time;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ut.modtime = index->file_sync_stamp;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (utime(index->filepath, &ut) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return index_set_syscall_error(index, "utime()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint maildir_index_sync(struct mail_index *index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mail_lock_type data_lock_type __attr_unused__,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int *changes)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist *uidlist;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen DIR *new_dirp;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct dirent *new_dent;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *new_dir;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(index->lock_type != MAIL_LOCK_SHARED);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (changes != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *changes = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_dir = t_strconcat(index->mailbox_path, "/new", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!maildir_new_scan_first_file(index, new_dir, &new_dirp, &new_dent))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen ret = maildir_index_lock_and_sync(index, changes, new_dirp, new_dent,
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen &uidlist);
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen if (uidlist != NULL)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen maildir_uidlist_close(uidlist);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (new_dirp != NULL) {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (closedir(new_dirp) < 0) {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen index_file_set_syscall_error(index, new_dir,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen "closedir()");
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen }
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen }
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen maildir_uidlist_unlock(index);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen return ret;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen}
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen