Change compress.sync_mailbox() to lock the compressed mailbox around both the tempfile sync and compress operations. This will prevent changes made inbetween the two syncs from being overwritten.
# HG changeset patch # User Kevin McCarthy <ke...@8t8.us> # Date 1478734909 28800 # Wed Nov 09 15:41:49 2016 -0800 # Node ID 6044c9d792c07d561a57fd501b6c8794f6b8c4b5 # Parent a49e229bbf3380fc6dc6e6e4cfb1072ebb512b48 Create mx_ops.sync operation. Refactor compress to use the mx_ops.sync. Change compress.sync_mailbox() to lock the compressed mailbox around both the tempfile sync and compress operations. This will prevent changes made inbetween the two syncs from being overwritten. diff --git a/compress.c b/compress.c --- a/compress.c +++ b/compress.c @@ -813,58 +813,72 @@ if (find_hook (MUTT_OPENHOOK, path)) return 1; else return 0; } /** - * mutt_comp_sync - Save changes to the compressed mailbox file + * sync_mailbox - Save changes to the compressed mailbox file * @ctx: Mailbox to sync * - * Changes in Mutt only affect the tmp file. Calling mutt_comp_sync() + * Changes in Mutt only affect the tmp file. Calling sync_mailbox() * will commit them to the compressed file. * * Returns: * 0: Success * -1: Failure */ -int -mutt_comp_sync (CONTEXT *ctx) +static int +sync_mailbox (CONTEXT *ctx, int *index_hint) { if (!ctx) return -1; COMPRESS_INFO *ci = ctx->compress_info; if (!ci) return -1; if (!ci->close) { mutt_error (_("Can't sync a compressed file without a close-hook")); return -1; } - /* TODO: need to refactor sync so we can lock around the - * path sync as well as the compress operation */ + struct mx_ops *ops = ci->child_ops; + if (!ops) + return -1; + if (!lock_realpath (ctx, 1)) { mutt_error (_("Unable to lock mailbox!")); return -1; } - int rc = execute_command (ctx, ci->close, _("Compressing %s")); + /* TODO: check if mailbox changed first! */ + + int rc = ops->sync (ctx, index_hint); + if (rc != 0) + { + unlock_realpath (ctx); + return rc; + } + + rc = execute_command (ctx, ci->close, _("Compressing %s")); if (rc == 0) + { + unlock_realpath (ctx); return -1; + } + + store_size (ctx); unlock_realpath (ctx); - store_size (ctx); - return 0; } /** * mutt_comp_valid_command - Is this command string allowed? * @cmd: Command string * * A valid command string must have both "%f" (from file) and "%t" (to file). @@ -891,14 +905,15 @@ * The message functions are delegated to mbox. */ struct mx_ops mx_comp_ops = { .open = open_mailbox, .open_append = open_append_mailbox, .close = close_mailbox, .check = check_mailbox, + .sync = sync_mailbox, .open_msg = open_message, .close_msg = close_message, .commit_msg = commit_message, .open_new_msg = open_new_message }; diff --git a/compress.h b/compress.h --- a/compress.h +++ b/compress.h @@ -18,14 +18,13 @@ #ifndef _COMPRESS_H_ #define _COMPRESS_H_ void mutt_free_compress_info (CONTEXT *ctx); int mutt_comp_can_append (CONTEXT *ctx); int mutt_comp_can_read (const char *path); -int mutt_comp_sync (CONTEXT *ctx); int mutt_comp_valid_command (const char *cmd); extern struct mx_ops mx_comp_ops; #endif /* _COMPRESS_H_ */ diff --git a/imap/imap.c b/imap/imap.c --- a/imap/imap.c +++ b/imap/imap.c @@ -2183,9 +2183,10 @@ .open = imap_open_mailbox, .open_append = imap_open_mailbox_append, .close = imap_close_mailbox, .open_msg = imap_fetch_message, .close_msg = imap_close_message, .commit_msg = imap_commit_message, .open_new_msg = imap_open_new_message, .check = imap_check_mailbox_reopen, + .sync = NULL, /* imap syncing is handled by imap_sync_mailbox */ }; diff --git a/mbox.c b/mbox.c --- a/mbox.c +++ b/mbox.c @@ -797,31 +797,32 @@ utime (ctx->path, &utimebuf); } /* return values: * 0 success * -1 failure */ -int mbox_sync_mailbox (CONTEXT *ctx, int *index_hint) +static int mbox_sync_mailbox (CONTEXT *ctx, int *index_hint) { char tempfile[_POSIX_PATH_MAX]; char buf[32]; int i, j, save_sort = SORT_ORDER; int rc = -1; int need_sort = 0; /* flag to resort mailbox if new mail arrives */ int first = -1; /* first message to be written */ LOFF_T offset; /* location in mailbox to write changed messages */ struct stat statbuf; struct m_update_t *newOffset = NULL; struct m_update_t *oldOffset = NULL; FILE *fp = NULL; progress_t progress; char msgbuf[STRING]; + BUFFY *tmp = NULL; /* sort message by their position in the mailbox on disk */ if (Sort != SORT_ORDER) { save_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers (ctx, 0); Sort = save_sort; @@ -1109,16 +1110,23 @@ ctx->hdrs[i]->index = j++; } } FREE (&newOffset); FREE (&oldOffset); unlink (tempfile); /* remove partial copy of the mailbox */ mutt_unblock_signals (); + if (option(OPTCHECKMBOXSIZE)) + { + tmp = mutt_find_mailbox (ctx->path); + if (tmp && tmp->new == 0) + mutt_update_mailbox (tmp); + } + return (0); /* signal success */ bail: /* Come here in case of disaster */ safe_fclose (&fp); /* restore offsets, as far as they are valid */ if (first >= 0 && oldOffset) @@ -1349,20 +1357,22 @@ .open = mbox_open_mailbox, .open_append = mbox_open_mailbox_append, .close = mbox_close_mailbox, .open_msg = mbox_open_message, .close_msg = mbox_close_message, .commit_msg = mbox_commit_message, .open_new_msg = mbox_open_new_message, .check = mbox_check_mailbox, + .sync = mbox_sync_mailbox, }; struct mx_ops mx_mmdf_ops = { .open = mbox_open_mailbox, .open_append = mbox_open_mailbox_append, .close = mbox_close_mailbox, .open_msg = mbox_open_message, .close_msg = mbox_close_message, .commit_msg = mmdf_commit_message, .open_new_msg = mbox_open_new_message, .check = mbox_check_mailbox, + .sync = mbox_sync_mailbox, }; diff --git a/mh.c b/mh.c --- a/mh.c +++ b/mh.c @@ -2531,20 +2531,22 @@ .open = maildir_open_mailbox, .open_append = maildir_open_mailbox_append, .close = mh_close_mailbox, .open_msg = maildir_open_message, .close_msg = mh_close_message, .commit_msg = maildir_commit_message, .open_new_msg = maildir_open_new_message, .check = maildir_check_mailbox, + .sync = mh_sync_mailbox, }; struct mx_ops mx_mh_ops = { .open = mh_open_mailbox, .open_append = mh_open_mailbox_append, .close = mh_close_mailbox, .open_msg = mh_open_message, .close_msg = mh_close_message, .commit_msg = mh_commit_message, .open_new_msg = mh_open_new_message, .check = mh_check_mailbox, + .sync = mh_sync_mailbox, }; diff --git a/mutt.h b/mutt.h --- a/mutt.h +++ b/mutt.h @@ -903,16 +903,17 @@ * - open_new_msg */ struct mx_ops { int (*open) (struct _context *); int (*open_append) (struct _context *, int flags); int (*close) (struct _context *); int (*check) (struct _context *ctx, int *index_hint); + int (*sync) (struct _context *ctx, int *index_hint); int (*open_msg) (struct _context *, struct _message *, int msgno); int (*close_msg) (struct _context *, struct _message *); int (*commit_msg) (struct _context *, struct _message *); int (*open_new_msg) (struct _message *, struct _context *, HEADER *); }; typedef struct _context { diff --git a/mx.c b/mx.c --- a/mx.c +++ b/mx.c @@ -677,66 +677,23 @@ mutt_pattern_free (&ctx->limit_pattern); safe_fclose (&ctx->fp); memset (ctx, 0, sizeof (CONTEXT)); } /* save changes to disk */ static int sync_mailbox (CONTEXT *ctx, int *index_hint) { - BUFFY *tmp = NULL; - int rc = -1; + if (!ctx->mx_ops || !ctx->mx_ops->sync) + return -1; if (!ctx->quiet) mutt_message (_("Writing %s..."), ctx->path); - switch (ctx->magic) - { - case MUTT_MBOX: - case MUTT_MMDF: - rc = mbox_sync_mailbox (ctx, index_hint); - if (option(OPTCHECKMBOXSIZE)) - tmp = mutt_find_mailbox (ctx->path); - break; - - case MUTT_MH: - case MUTT_MAILDIR: - rc = mh_sync_mailbox (ctx, index_hint); - break; - -#ifdef USE_IMAP - case MUTT_IMAP: - /* extra argument means EXPUNGE */ - rc = imap_sync_mailbox (ctx, 1, index_hint); - break; -#endif /* USE_IMAP */ - -#ifdef USE_POP - case MUTT_POP: - rc = pop_sync_mailbox (ctx, index_hint); - break; -#endif /* USE_POP */ - } - -#if 0 - if (!ctx->quiet && !ctx->shutup && rc == -1) - mutt_error ( _("Could not synchronize mailbox %s!"), ctx->path); -#endif - - if (tmp && tmp->new == 0) - mutt_update_mailbox (tmp); - -#ifdef USE_COMPRESSED - /* If everything went well, the mbox handler saved the changes to our - * temporary file. Next, mutt_comp_sync() will compress the temporary file. */ - if ((rc == 0) && ctx->compress_info) - return mutt_comp_sync (ctx); -#endif - - return rc; + return ctx->mx_ops->sync (ctx, index_hint); } /* move deleted mails to the trash folder */ static int trash_append (CONTEXT *ctx) { CONTEXT ctx_trash; int i; struct stat st, stc; diff --git a/mx.h b/mx.h --- a/mx.h +++ b/mx.h @@ -42,25 +42,23 @@ #endif }; WHERE short DefaultMagic INITVAL (MUTT_MBOX); #define MMDF_SEP "\001\001\001\001\n" #define MAXLOCKATTEMPT 5 -int mbox_sync_mailbox (CONTEXT *, int *); int mbox_lock_mailbox (CONTEXT *, int, int); int mbox_parse_mailbox (CONTEXT *); int mmdf_parse_mailbox (CONTEXT *); void mbox_unlock_mailbox (CONTEXT *); int mbox_check_empty (const char *); void mbox_reset_atime (CONTEXT *, struct stat *); -int mh_sync_mailbox (CONTEXT *, int *); int mh_check_empty (const char *); int maildir_check_empty (const char *); FILE *maildir_open_find_message (const char *, const char *); int mbox_strict_cmp_headers (const HEADER *, const HEADER *); int mutt_reopen_mailbox (CONTEXT *, int *); diff --git a/pop.c b/pop.c --- a/pop.c +++ b/pop.c @@ -659,17 +659,17 @@ } static int pop_close_message (CONTEXT *ctx, MESSAGE *msg) { return safe_fclose (&msg->fp); } /* update POP mailbox - delete messages from server */ -int pop_sync_mailbox (CONTEXT *ctx, int *index_hint) +static int pop_sync_mailbox (CONTEXT *ctx, int *index_hint) { int i, j, ret = 0; char buf[LONG_STRING]; POP_DATA *pop_data = (POP_DATA *)ctx->data; progress_t progress; #ifdef USE_HCACHE header_cache_t *hc = NULL; #endif @@ -939,9 +939,10 @@ .open = pop_open_mailbox, .open_append = NULL, .close = pop_close_mailbox, .open_msg = pop_fetch_message, .close_msg = pop_close_message, .check = pop_check_mailbox, .commit_msg = NULL, .open_new_msg = NULL, + .sync = pop_sync_mailbox, }; diff --git a/pop.h b/pop.h --- a/pop.h +++ b/pop.h @@ -100,15 +100,14 @@ int pop_open_connection (POP_DATA *); int pop_query_d (POP_DATA *, char *, size_t, char *); int pop_fetch_data (POP_DATA *, char *, progress_t *, int (*funct) (char *, void *), void *); int pop_reconnect (CONTEXT *); void pop_logout (CONTEXT *); void pop_error (POP_DATA *, char *); /* pop.c */ -int pop_sync_mailbox (CONTEXT *, int *); int pop_close_mailbox (CONTEXT *); void pop_fetch_mail (void); extern struct mx_ops mx_pop_ops; #endif