which aren't reliable.
--HG--
branch : HEAD
ino_t mbox_ino;
/* last maildir sync: */
- dev_t uidlist_dev;
- ino_t uidlist_ino;
-
+ time_t uidlist_mtime;
int maildir_lock_fd;
int fd; /* opened index file */
0, 0, 0, 0, 0, 0, { 0, 0, 0 }, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
- 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0
#endif
/* defaults - same as above but prefixed with mail_index_. */
return FALSE;
}
+ if (uid_rec.uid > uid &&
+ (hash_rec->action == MAILDIR_FILE_ACTION_UPDATE_FLAGS ||
+ hash_rec->action == MAILDIR_FILE_ACTION_NONE)) {
+ /* it's UID has changed */
+ hash_rec->action = MAILDIR_FILE_ACTION_UPDATE_CONTENT;
+
+ /* make sure filename is not invalidated by expunge */
+ hash_insert(files, p_strdup(pool, fname), hash_rec);
+ }
+
switch (hash_rec->action) {
case MAILDIR_FILE_ACTION_EXPUNGE:
if (!index->expunge(index, rec, seq, TRUE))
i_assert(hash_rec->action == MAILDIR_FILE_ACTION_NEW);
/* make sure we set the same UID for it. */
- i_assert(index->header->next_uid <= uid_rec.uid);
+ if (index->header->next_uid > uid_rec.uid) {
+ index_set_corrupted(index,
+ "index.next_uid (%u) > "
+ "uid_rec.uid (%u)",
+ index->header->next_uid,
+ uid_rec.uid);
+ return FALSE;
+ }
index->header->next_uid = uid_rec.uid;
hash_rec->action = MAILDIR_FILE_ACTION_NONE;
struct utimbuf ut;
struct maildir_uidlist *uidlist;
const char *uidlist_path, *cur_dir, *new_dir;
- time_t index_mtime;
+ time_t index_mtime, uidlist_mtime;
int cur_changed;
*uidlist_r = uidlist = NULL;
memset(&st, 0, sizeof(st));
cur_changed = TRUE;
+ uidlist_mtime = 0;
} else {
- /* FIXME: save device and inode into index header, so we don't
+ /* FIXME: save mtime into index header, so we don't
have to read it every time mailbox is opened */
+ uidlist_mtime = st.st_mtime;
cur_changed = index_mtime != std.st_mtime ||
- st.st_ino != index->uidlist_ino ||
- !CMP_DEV_T(st.st_dev, index->uidlist_dev);
+ index->uidlist_mtime != uidlist_mtime;
}
if (new_dirp != NULL || cur_changed) {
return TRUE;
}
- if (fstat(index->maildir_lock_fd, &st) < 0) {
- return index_file_set_syscall_error(index, uidlist_path,
- "fstat()");
- }
-
- if (!maildir_uidlist_rewrite(index))
+ if (!maildir_uidlist_rewrite(index, &uidlist_mtime))
return FALSE;
}
/* uidlist file synced */
- index->uidlist_ino = st.st_ino;
- index->uidlist_dev = st.st_dev;
+ index->uidlist_mtime = uidlist_mtime;
/* update sync stamp */
index->file_sync_stamp = std.st_mtime;
#include <stdio.h>
#include <sys/stat.h>
+#include <utime.h>
/* how many seconds to wait before overriding uidlist.lock */
#define UIDLIST_LOCK_STALE_TIMEOUT (60*5)
i_free(uidlist);
}
-int maildir_uidlist_rewrite(struct mail_index *index)
+static int maildir_uidlist_rewrite_fd(struct mail_index *index,
+ const char *temp_path, time_t *mtime)
{
struct mail_index_record *rec;
- const char *temp_path, *db_path, *p, *fname;
+ struct utimbuf ut;
+ const char *p, *fname;
string_t *str;
size_t len;
- int failed = FALSE;
-
- i_assert(INDEX_IS_UIDLIST_LOCKED(index));
-
- if (index->lock_type == MAIL_LOCK_UNLOCK) {
- if (!index->set_lock(index, MAIL_LOCK_SHARED))
- return FALSE;
- }
-
- temp_path = t_strconcat(index->mailbox_path,
- "/" MAILDIR_UIDLIST_NAME ".lock", NULL);
str = t_str_new(4096);
str_printfa(str, "1 %u %u\n",
while (rec != NULL) {
fname = maildir_get_location(index, rec);
if (fname == NULL)
- break;
+ return FALSE;
p = strchr(fname, ':');
len = p == NULL ? strlen(fname) : (size_t)(p-fname);
str_data(str), str_len(str)) < 0) {
index_file_set_syscall_error(index, temp_path,
"write_full()");
- break;
+ return FALSE;
}
str_truncate(str, 0);
}
if (write_full(index->maildir_lock_fd,
str_data(str), str_len(str)) < 0) {
index_file_set_syscall_error(index, temp_path, "write_full()");
- failed = TRUE;
+ return FALSE;
}
- if (fdatasync(index->maildir_lock_fd) < 0) {
- index_file_set_syscall_error(index, temp_path, "fdatasync()");
- failed = TRUE;
+ /* uidlist's mtime must grow every time */
+ *mtime = ioloop_time > *mtime ? ioloop_time : *mtime + 1;
+ ut.actime = ioloop_time;
+ ut.modtime = *mtime;
+ if (utime(temp_path, &ut) < 0)
+ index_set_syscall_error(index, "utime()");
+
+ if (fsync(index->maildir_lock_fd) < 0) {
+ index_file_set_syscall_error(index, temp_path, "fsync()");
+ return FALSE;
}
+
+ return TRUE;
+}
+
+int maildir_uidlist_rewrite(struct mail_index *index, time_t *mtime)
+{
+ const char *temp_path, *db_path;
+ int failed = FALSE;
+
+ i_assert(INDEX_IS_UIDLIST_LOCKED(index));
+
+ if (index->lock_type == MAIL_LOCK_UNLOCK) {
+ if (!index->set_lock(index, MAIL_LOCK_SHARED))
+ return FALSE;
+ }
+
+ temp_path = t_strconcat(index->mailbox_path,
+ "/" MAILDIR_UIDLIST_NAME ".lock", NULL);
+
+ failed = !maildir_uidlist_rewrite_fd(index, temp_path, mtime);
if (close(index->maildir_lock_fd) < 0) {
index_file_set_syscall_error(index, temp_path, "close()");
failed = TRUE;
}
index->maildir_lock_fd = -1;
- if (rec == NULL) {
+ if (!failed) {
db_path = t_strconcat(index->mailbox_path,
"/" MAILDIR_UIDLIST_NAME, NULL);
int maildir_uidlist_try_lock(struct mail_index *index);
void maildir_uidlist_unlock(struct mail_index *index);
-int maildir_uidlist_rewrite(struct mail_index *index);
+int maildir_uidlist_rewrite(struct mail_index *index, time_t *mtime);
struct maildir_uidlist *maildir_uidlist_open(struct mail_index *index);
void maildir_uidlist_close(struct maildir_uidlist *uidlist);