1
/* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */
1
/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
4
4
Version 1 format has been used for most versions of Dovecot up to v1.0.x.
30
30
#include "istream.h"
31
31
#include "ostream.h"
33
#include "hex-binary.h"
34
33
#include "file-dotlock.h"
35
34
#include "close-keep-errno.h"
36
35
#include "nfs-workarounds.h"
37
36
#include "eacces-error.h"
38
37
#include "maildir-storage.h"
39
#include "maildir-sync.h"
40
38
#include "maildir-filename.h"
41
39
#include "maildir-uidlist.h"
54
52
#define UIDLIST_IS_LOCKED(uidlist) \
55
53
((uidlist)->lock_count > 0)
56
#define UIDLIST_ALLOW_WRITING(uidlist) \
57
(UIDLIST_IS_LOCKED(uidlist) || (uidlist)->mbox == NULL)
59
55
struct maildir_uidlist_rec {
137
135
bool nonblock, bool refresh,
138
136
bool refresh_when_locked)
140
struct mailbox *box = &uidlist->mbox->box;
138
struct mailbox *box = uidlist->box;
139
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
141
140
const char *control_dir, *path;
143
142
const enum dotlock_create_flags dotlock_flags =
156
index_storage_lock_notify_reset(&uidlist->mbox->box);
155
index_storage_lock_notify_reset(uidlist->box);
158
157
control_dir = mailbox_list_get_path(box->list, box->name,
159
158
MAILBOX_LIST_PATH_TYPE_CONTROL);
160
159
path = t_strconcat(control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
162
161
for (i = 0;; i++) {
163
old_mask = umask(0777 & ~box->file_create_mode);
162
old_mask = umask(0777 & ~perm->file_create_mode);
164
163
ret = file_dotlock_create(&uidlist->dotlock_settings, path,
165
164
dotlock_flags, &uidlist->dotlock);
173
172
MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
176
if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT ||
177
uidlist->mbox == NULL) {
175
if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
178
176
if (errno == EACCES) {
179
177
mail_storage_set_critical(box->storage, "%s",
180
178
eacces_error_get_creating("file_dotlock_create", path));
232
230
return uidlist->initial_read;
233
bool maildir_uidlist_is_open(struct maildir_uidlist *uidlist)
235
return uidlist->fd != -1;
235
238
void maildir_uidlist_unlock(struct maildir_uidlist *uidlist)
237
240
i_assert(uidlist->lock_count > 0);
257
260
struct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox)
262
struct mailbox *box = &mbox->box;
259
263
struct maildir_uidlist *uidlist;
260
264
const char *control_dir;
262
control_dir = mailbox_list_get_path(mbox->box.list, mbox->box.name,
266
control_dir = mailbox_list_get_path(box->list, box->name,
263
267
MAILBOX_LIST_PATH_TYPE_CONTROL);
265
269
uidlist = i_new(struct maildir_uidlist, 1);
266
uidlist->mbox = mbox;
271
uidlist->mhdr = &mbox->maildir_hdr;
267
272
uidlist->fd = -1;
268
273
uidlist->path = i_strconcat(control_dir, "/"MAILDIR_UIDLIST_NAME, NULL);
269
274
i_array_init(&uidlist->records, 128);
276
281
uidlist->dotlock_settings.use_io_notify = TRUE;
277
282
uidlist->dotlock_settings.use_excl_lock =
278
mbox->box.storage->set->dotlock_use_excl;
283
box->storage->set->dotlock_use_excl;
279
284
uidlist->dotlock_settings.nfs_flush =
280
mbox->box.storage->set->mail_nfs_storage;
285
box->storage->set->mail_nfs_storage;
281
286
uidlist->dotlock_settings.timeout =
282
mail_storage_get_lock_timeout(&mbox->storage->storage,
287
mail_storage_get_lock_timeout(box->storage,
283
288
MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT + 2);
284
289
uidlist->dotlock_settings.stale_timeout =
285
290
MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT;
286
291
uidlist->dotlock_settings.callback = dotlock_callback;
287
uidlist->dotlock_settings.context = &mbox->box;
292
uidlist->dotlock_settings.context = box;
288
293
uidlist->dotlock_settings.temp_prefix = mbox->storage->temp_prefix;
292
297
static void maildir_uidlist_close(struct maildir_uidlist *uidlist)
294
struct mail_storage *storage = uidlist->mbox->box.storage;
299
struct mail_storage *storage = uidlist->box->storage;
296
301
if (uidlist->fd != -1) {
297
302
if (close(uidlist->fd) < 0) {
368
373
static void maildir_uidlist_update_hdr(struct maildir_uidlist *uidlist,
369
374
const struct stat *st)
371
struct maildir_index_header *mhdr;
373
if (uidlist->mbox == NULL) {
374
/* dbox is using this */
378
mhdr = &uidlist->mbox->maildir_hdr;
376
struct maildir_index_header *mhdr = uidlist->mhdr;
379
378
if (mhdr->uidlist_mtime == 0 && uidlist->version != UIDLIST_VERSION) {
380
379
/* upgrading from older verson. don't update the
381
380
uidlist times until it uses the new format */
600
598
*next_uid_r = strtoul(value, NULL, 10);
602
600
case MAILDIR_UIDLIST_HDR_EXT_GUID:
603
buf = buffer_create_dynamic(pool_datastack_create(),
605
if (hex_to_binary(value, buf) < 0 ||
606
buf->used != MAIL_GUID_128_SIZE) {
601
if (guid_128_from_string(value,
602
uidlist->mailbox_guid) < 0) {
607
603
maildir_uidlist_set_corrupted(uidlist,
608
604
"Invalid mailbox GUID: %s", value);
611
memcpy(uidlist->mailbox_guid, buf->data,
612
sizeof(uidlist->mailbox_guid));
613
607
uidlist->have_mailbox_guid = TRUE;
702
696
maildir_uidlist_update_read(struct maildir_uidlist *uidlist,
703
697
bool *retry_r, bool try_retry)
705
struct mail_storage *storage = uidlist->mbox->box.storage;
699
struct mail_storage *storage = uidlist->box->storage;
706
700
const char *line;
707
701
uint32_t orig_next_uid, orig_uid_validity;
708
702
struct istream *input;
710
704
uoff_t last_read_offset;
706
bool readonly = FALSE;
713
708
*retry_r = FALSE;
715
710
if (uidlist->fd == -1) {
716
711
fd = nfs_safe_open(uidlist->path, O_RDWR);
712
if (fd == -1 && errno == EACCES) {
713
fd = nfs_safe_open(uidlist->path, O_RDONLY);
718
717
if (errno != ENOENT) {
719
718
mail_storage_set_critical(storage,
846
847
maildir_uidlist_stat(struct maildir_uidlist *uidlist, struct stat *st_r)
848
struct mail_storage *storage = uidlist->mbox->box.storage;
849
struct mail_storage *storage = uidlist->box->storage;
850
851
if (storage->set->mail_nfs_storage) {
851
852
nfs_flush_file_handle_cache(uidlist->path);
926
927
uidlist->fd = nfs_safe_open(uidlist->path, O_RDWR);
928
if (uidlist->fd == -1 && errno == EACCES) {
929
uidlist->fd = nfs_safe_open(uidlist->path, O_RDONLY);
930
uidlist->recreate_on_change = TRUE;
927
932
if (uidlist->fd == -1 && errno != ENOENT) {
928
mail_storage_set_critical(uidlist->mbox->box.storage,
933
mail_storage_set_critical(uidlist->box->storage,
929
934
"open(%s) failed: %m", uidlist->path);
965
970
int maildir_uidlist_refresh_fast_init(struct maildir_uidlist *uidlist)
967
const struct maildir_index_header *mhdr = &uidlist->mbox->maildir_hdr;
968
struct mail_index *index = uidlist->mbox->box.index;
972
const struct maildir_index_header *mhdr = uidlist->mhdr;
973
struct mail_index *index = uidlist->box->index;
969
974
struct mail_index_view *view;
970
975
const struct mail_index_header *hdr;
1035
1040
enum maildir_uidlist_rec_flag *flags_r,
1036
1041
const char **fname_r)
1040
ret = maildir_uidlist_lookup_nosync(uidlist, uid, flags_r, fname_r);
1044
if (uidlist->fd != -1 || uidlist->mbox == NULL) {
1045
/* refresh uidlist and check again in case it was added
1046
after the last mailbox sync */
1047
if (maildir_uidlist_refresh(uidlist) < 0)
1050
/* the uidlist doesn't exist. */
1051
if (maildir_storage_sync_force(uidlist->mbox, uid) < 0)
1056
ret = maildir_uidlist_lookup_nosync(uidlist, uid,
1063
int maildir_uidlist_lookup_nosync(struct maildir_uidlist *uidlist, uint32_t uid,
1064
enum maildir_uidlist_rec_flag *flags_r,
1065
const char **fname_r)
1067
1043
struct maildir_uidlist_rec *rec;
1111
1087
int maildir_uidlist_get_mailbox_guid(struct maildir_uidlist *uidlist,
1112
uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
1088
guid_128_t mailbox_guid)
1114
1090
if (!uidlist->initial_hdr_read) {
1115
1091
if (maildir_uidlist_refresh(uidlist) < 0)
1120
1096
if (maildir_uidlist_update(uidlist) < 0)
1123
memcpy(mailbox_guid, uidlist->mailbox_guid, MAIL_GUID_128_SIZE);
1099
memcpy(mailbox_guid, uidlist->mailbox_guid, GUID_128_SIZE);
1127
1103
void maildir_uidlist_set_mailbox_guid(struct maildir_uidlist *uidlist,
1128
const uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
1104
const guid_128_t mailbox_guid)
1130
1106
if (memcmp(uidlist->mailbox_guid, mailbox_guid,
1131
1107
sizeof(uidlist->mailbox_guid)) != 0) {
1229
1205
const struct mail_index_header *hdr;
1231
if (uidlist->mbox->box.opened) {
1232
hdr = mail_index_get_header(uidlist->mbox->box.view);
1207
if (uidlist->box->opened) {
1208
hdr = mail_index_get_header(uidlist->box->view);
1233
1209
if (hdr->uid_validity != 0) {
1234
1210
uidlist->uid_validity = hdr->uid_validity;
1238
1214
uidlist->uid_validity =
1239
maildir_get_uidvalidity_next(uidlist->mbox->box.list);
1215
maildir_get_uidvalidity_next(uidlist->box->list);
1242
1218
static int maildir_uidlist_write_fd(struct maildir_uidlist *uidlist, int fd,
1243
1219
const char *path, unsigned int first_idx,
1244
1220
uoff_t *file_size_r)
1246
struct mail_storage *storage = uidlist->mbox->box.storage;
1222
struct mail_storage *storage = uidlist->box->storage;
1247
1223
struct maildir_uidlist_iter_ctx *iter;
1248
1224
struct ostream *output;
1249
1225
struct maildir_uidlist_rec *rec;
1266
1242
if (uidlist->uid_validity == 0)
1267
1243
maildir_uidlist_generate_uid_validity(uidlist);
1268
1244
if (!uidlist->have_mailbox_guid)
1269
mail_generate_guid_128(uidlist->mailbox_guid);
1245
guid_128_generate(uidlist->mailbox_guid);
1271
1247
i_assert(uidlist->next_uid > 0);
1272
1248
str_printfa(str, "%u %c%u %c%u %c%s", uidlist->version,
1275
1251
MAILDIR_UIDLIST_HDR_EXT_NEXT_UID,
1276
1252
uidlist->next_uid,
1277
1253
MAILDIR_UIDLIST_HDR_EXT_GUID,
1278
binary_to_hex(uidlist->mailbox_guid,
1279
sizeof(uidlist->mailbox_guid)));
1254
guid_128_to_string(uidlist->mailbox_guid));
1280
1255
if (str_len(uidlist->hdr_extensions) > 0) {
1281
1256
str_append_c(str, ' ');
1282
1257
str_append_str(str, uidlist->hdr_extensions);
1349
1324
/* we could get here when opening and locking mailbox,
1350
1325
before index files have been opened. */
1351
if (!uidlist->mbox->box.opened)
1326
if (!uidlist->box->opened)
1354
mail_index_refresh(uidlist->mbox->box.index);
1355
view = mail_index_view_open(uidlist->mbox->box.index);
1329
mail_index_refresh(uidlist->box->index);
1330
view = mail_index_view_open(uidlist->box->index);
1356
1331
count = array_count(&uidlist->records);
1357
1332
hdr = mail_index_get_header(view);
1358
1333
if (count * UIDLIST_COMPRESS_PERCENTAGE / 100 <= hdr->messages_count) {
1398
1373
static int maildir_uidlist_recreate(struct maildir_uidlist *uidlist)
1400
struct mailbox *box = &uidlist->mbox->box;
1375
struct mailbox *box = uidlist->box;
1376
const struct mailbox_permissions *perm = mailbox_get_permissions(box);
1401
1377
const char *control_dir, *temp_path;
1402
1378
struct stat st;
1403
1379
mode_t old_mask;
1414
1390
"/" MAILDIR_UIDLIST_NAME ".tmp", NULL);
1416
1392
for (i = 0;; i++) {
1417
old_mask = umask(0777 & ~box->file_create_mode);
1393
old_mask = umask(0777 & ~perm->file_create_mode);
1418
1394
fd = open(temp_path, O_RDWR | O_CREAT | O_TRUNC, 0777);
1419
1395
umask(old_mask);
1423
if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT ||
1424
uidlist->mbox == NULL) {
1399
if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) {
1425
1400
mail_storage_set_critical(box->storage,
1426
1401
"open(%s, O_CREAT) failed: %m", temp_path);
1429
1404
/* the control dir doesn't exist. create it unless the whole
1430
1405
mailbox was just deleted. */
1431
if (!maildir_set_deleted(&uidlist->mbox->box))
1406
if (!maildir_set_deleted(uidlist->box))
1435
if (box->file_create_gid != (gid_t)-1 &&
1436
fchown(fd, (uid_t)-1, box->file_create_gid) < 0) {
1410
if (perm->file_create_gid != (gid_t)-1 &&
1411
fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
1437
1412
if (errno == EPERM) {
1438
1413
mail_storage_set_critical(box->storage, "%s",
1439
1414
eperm_error_get_chgrp("fchown", temp_path,
1440
box->file_create_gid,
1441
box->file_create_gid_origin));
1415
perm->file_create_gid,
1416
perm->file_create_gid_origin));
1443
1418
mail_storage_set_critical(box->storage,
1444
1419
"fchown(%s) failed: %m", temp_path);
1535
1510
static int maildir_uidlist_sync_update(struct maildir_uidlist_sync_ctx *ctx)
1537
1512
struct maildir_uidlist *uidlist = ctx->uidlist;
1538
struct mail_storage *storage = uidlist->mbox->box.storage;
1513
struct mail_storage *storage = uidlist->box->storage;
1539
1514
struct stat st;
1540
1515
uoff_t file_size;
1547
1522
i_assert(uidlist->initial_hdr_read);
1548
1523
if (maildir_uidlist_open_latest(uidlist) < 0)
1525
if (uidlist->recreate_on_change)
1526
return maildir_uidlist_recreate(uidlist);
1551
1528
i_assert(ctx->first_unwritten_pos != (unsigned int)-1);
1647
1624
*sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1);
1648
1625
ctx->uidlist = uidlist;
1649
1626
ctx->sync_flags = sync_flags;
1650
ctx->partial = (!locked && ctx->uidlist->mbox != NULL) ||
1627
ctx->partial = !locked ||
1651
1628
(sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0;
1652
1629
ctx->locked = locked;
1653
1630
ctx->first_unwritten_pos = (unsigned int)-1;
1711
1688
if (uid != 0) {
1712
1689
if (rec->uid != uid && rec->uid != (uint32_t)-1) {
1713
mail_storage_set_critical(uidlist->mbox->box.storage,
1690
mail_storage_set_critical(uidlist->box->storage,
1714
1691
"Maildir: %s changed UID %u -> %u",
1715
1692
filename, rec->uid, uid);
1728
rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
1705
rec->flags &= ~MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
1706
rec->flags = (rec->flags | flags) &
1707
~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
1729
1708
rec->filename = p_strdup(uidlist->record_pool, filename);
1730
1709
hash_table_insert(uidlist->files, rec->filename, rec);
1778
1757
for (p = filename; *p != '\0'; p++) {
1779
1758
if (*p == 13 || *p == 10) {
1780
struct mailbox *box = &uidlist->mbox->box;
1759
struct mailbox *box = uidlist->box;
1782
1761
dir = mailbox_list_get_path(box->list, box->name,
1783
1762
MAILBOX_LIST_PATH_TYPE_MAILBOX);
1807
1786
MAILDIR_UIDLIST_REC_FLAG_MOVED);
1809
1788
old_rec = hash_table_lookup(uidlist->files, filename);
1810
i_assert(old_rec != NULL || UIDLIST_ALLOW_WRITING(uidlist));
1789
i_assert(old_rec != NULL || UIDLIST_IS_LOCKED(uidlist));
1812
1791
rec = p_new(ctx->record_pool, struct maildir_uidlist_rec, 1);
1885
void maildir_uidlist_update_fname(struct maildir_uidlist *uidlist,
1886
const char *filename)
1888
struct maildir_uidlist_rec *rec;
1890
rec = hash_table_lookup(uidlist->files, filename);
1894
rec->flags &= ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
1895
if (strcmp(rec->filename, filename) != 0)
1896
rec->filename = p_strdup(uidlist->record_pool, filename);
1907
1900
maildir_uidlist_get_full_filename(struct maildir_uidlist *uidlist,
1908
1901
const char *filename)
1931
1924
struct maildir_uidlist_rec **recs;
1932
1925
unsigned int dest, count;
1934
i_assert(UIDLIST_ALLOW_WRITING(ctx->uidlist));
1927
i_assert(UIDLIST_IS_LOCKED(ctx->uidlist));
1935
1928
i_assert(ctx->first_new_pos != (unsigned int)-1);
1937
1930
if (ctx->first_unwritten_pos == (unsigned int)-1)
2015
2008
/* mbox=NULL means we're coming from dbox rebuilding code.
2016
2009
the dbox is already locked, so allow uidlist recreation */
2017
i_assert(ctx->locked || !ctx->changed || ctx->uidlist->mbox == NULL);
2010
i_assert(ctx->locked || !ctx->changed);
2018
2011
if ((ctx->changed || maildir_uidlist_want_compress(ctx)) &&
2019
!ctx->failed && (ctx->locked || ctx->uidlist->mbox == NULL)) {
2012
!ctx->failed && ctx->locked) {
2021
2014
if (maildir_uidlist_sync_update(ctx) < 0) {
2022
2015
/* we couldn't write everything we wanted. make