static const char *
maildir_copy_get_preserved_fname(struct maildir_mailbox *src_mbox,
- struct maildir_mailbox *dest_mbox,
uint32_t uid)
{
enum maildir_uidlist_rec_flag flags;
const char *fname;
- /* see if the filename exists in destination maildir's
- uidlist. if it doesn't, we can use it. otherwise generate
- a new filename. FIXME: There's a race condition here if
- another process is just doing the same copy. */
if (maildir_uidlist_lookup(src_mbox->uidlist, uid, &flags,
&fname) <= 0)
return NULL;
- if (maildir_uidlist_refresh(dest_mbox->uidlist) <= 0)
- return NULL;
- if (maildir_uidlist_get_full_filename(dest_mbox->uidlist,
- fname) != NULL) {
- /* already exists in destination */
- return NULL;
- }
/* fname may be freed by a later uidlist sync. make sure it gets
strduped. */
return t_strcut(t_strdup(fname), ':');
if (dest_mbox->storage->set->maildir_copy_preserve_filename &&
src_mbox != NULL) {
- filename = maildir_copy_get_preserved_fname(src_mbox, dest_mbox,
+ filename = maildir_copy_get_preserved_fname(src_mbox,
mail->uid);
}
if (filename == NULL) {
}
/* hardlinked to tmp/, treat as normal copied mail */
- maildir_save_add(ctx, do_ctx.dest_fname);
+ maildir_save_add(ctx, do_ctx.dest_fname, do_ctx.preserve_filename);
return 1;
}
uint32_t first_seq, seq, last_nonrecent_uid;
unsigned int have_keywords:1;
+ unsigned int have_preserved_filenames:1;
unsigned int locked:1;
unsigned int failed:1;
unsigned int last_save_finished:1;
}
struct maildir_filename *
-maildir_save_add(struct mail_save_context *_ctx, const char *base_fname)
+maildir_save_add(struct mail_save_context *_ctx, const char *base_fname,
+ bool preserve_filename)
{
struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
struct maildir_filename *mf;
ctx->last_nonrecent_uid < _ctx->uid)
ctx->last_nonrecent_uid = _ctx->uid;
-
/* now, we want to be able to rollback the whole append session,
so we'll just store the name of this temp file and move it later
into new/ or cur/. */
mf->flags = _ctx->flags;
mf->size = (uoff_t)-1;
mf->vsize = (uoff_t)-1;
+ mf->preserve_filename = preserve_filename;
+ if (preserve_filename)
+ ctx->have_preserved_filenames = TRUE;
ctx->file_last = mf;
i_assert(*ctx->files_tail == NULL);
ctx->input = i_stream_create_crlf(input);
else
ctx->input = i_stream_create_lf(input);
- mf = maildir_save_add(_ctx, fname);
- if (fname == _ctx->guid)
- mf->preserve_filename = TRUE;
+ mf = maildir_save_add(_ctx, fname, fname == _ctx->guid);
}
} T_END;
/* we want to assign UIDs, we must lock uidlist */
} else if (ctx->have_keywords) {
/* keywords file updating relies on uidlist lock. */
+ } else if (ctx->have_preserved_filenames) {
+ /* we're trying to use some potentially existing filenames.
+ we must lock to avoid race conditions where two sessions
+ try to save the same filename. */
} else {
/* no requirement to lock uidlist. if we happen to get a lock,
assign uids. */
uint32_t old_uid, uint32_t new_uid);
struct maildir_filename *
-maildir_save_add(struct mail_save_context *_ctx, const char *base_fname);
+maildir_save_add(struct mail_save_context *_ctx, const char *base_fname,
+ bool preserve_filename);
const char *maildir_save_file_get_path(struct mailbox_transaction_context *t,
uint32_t seq);