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

Reply via email to