static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path, struct maildir_index_sync_context *ctx) { struct mailbox *box = &mbox->box; struct stat st; const char *dir, *fname, *newfname, *newpath; enum mail_index_sync_type sync_type; uint8_t flags8; ctx->flag_change_count++; fname = strrchr(path, '/'); i_assert(fname != NULL); fname++; dir = t_strdup_until(path, fname); i_assert(*fname != '\0'); /* get the current flags and keywords */ maildir_filename_flags_get(ctx->keywords_sync_ctx, fname, &ctx->flags, &ctx->keywords); /* apply changes */ flags8 = ctx->flags; index_sync_changes_apply(ctx->sync_changes, NULL, &flags8, &ctx->keywords, &sync_type); ctx->flags = flags8; /* and try renaming with the new name */ newfname = maildir_filename_flags_kw_set(ctx->keywords_sync_ctx, fname, ctx->flags, &ctx->keywords); newpath = t_strconcat(dir, newfname, NULL); if (strcmp(path, newpath) == 0) { /* just make sure that the file still exists. avoid rename() here because it's slow on HFS. */ if (stat(path, &st) < 0) { if (errno == ENOENT) return 0; mail_storage_set_critical(box->storage, "stat(%s) failed: %m", path); return -1; } } else { if (rename(path, newpath) < 0) { if (errno == ENOENT) return 0; if (!ENOSPACE(errno) && errno != EACCES) { mail_storage_set_critical(box->storage, "rename(%s, %s) failed: %m", path, newpath); } return -1; } } if (box->v.sync_notify != NULL) { box->v.sync_notify(box, ctx->uid, index_sync_type_convert(sync_type)); } return 1; }
static const char * maildir_filename_guess(struct maildir_mailbox *mbox, uint32_t uid, const char *fname, enum maildir_uidlist_rec_flag *uidlist_flags, bool *have_flags_r) { struct mail_index_view *view = mbox->flags_view; struct maildir_keywords_sync_ctx *kw_ctx; enum mail_flags flags; ARRAY_TYPE(keyword_indexes) keywords; const char *p; uint32_t seq; if (view == NULL || !mail_index_lookup_seq(view, uid, &seq)) { *have_flags_r = FALSE; return fname; } t_array_init(&keywords, 32); mail_index_lookup_view_flags(view, seq, &flags, &keywords); if (array_count(&keywords) == 0) { *have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0; fname = maildir_filename_flags_set(fname, flags); } else { *have_flags_r = TRUE; kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords, mbox->box.index); fname = maildir_filename_flags_kw_set(kw_ctx, fname, flags, &keywords); maildir_keywords_sync_deinit(&kw_ctx); } if (*have_flags_r) { /* don't even bother looking into new/ dir */ *uidlist_flags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; } else if ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_MOVED) == 0 && ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 || mailbox_recent_flags_have_uid(&mbox->box, uid))) { /* probably in new/ dir, drop ":2," from fname */ *uidlist_flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; p = strrchr(fname, MAILDIR_INFO_SEP); if (p != NULL) fname = t_strdup_until(fname, p); } return fname; }
static bool maildir_get_dest_filename(struct maildir_save_context *ctx, struct maildir_filename *mf, const char **fname_r) { const char *basename = mf->dest_basename; if (mf->size != (uoff_t)-1 && !mf->preserve_filename) { basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename, MAILDIR_EXTRA_FILE_SIZE, mf->size); } if (mf->vsize != (uoff_t)-1 && !mf->preserve_filename) { basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename, MAILDIR_EXTRA_VIRTUAL_SIZE, mf->vsize); } if (mf->keywords_count == 0) { if ((mf->flags & MAIL_FLAGS_MASK) == MAIL_RECENT) { *fname_r = basename; return TRUE; } *fname_r = maildir_filename_flags_set(basename, mf->flags & MAIL_FLAGS_MASK); return FALSE; } i_assert(ctx->keywords_sync_ctx != NULL || mf->keywords_count == 0); buffer_create_from_const_data(&ctx->keywords_buffer, mf + 1, mf->keywords_count * sizeof(unsigned int)); *fname_r = maildir_filename_flags_kw_set(ctx->keywords_sync_ctx, basename, mf->flags & MAIL_FLAGS_MASK, &ctx->keywords_array); return FALSE; }