diff src/memfile.c @ 16823:b1b7c7a31679 v8.1.1413

patch 8.1.1413: error when the drive of the swap file was disconnected commit https://github.com/vim/vim/commit/b58a4b938c4bc7e0499700859bd7abba9acc5b11 Author: Bram Moolenaar <Bram@vim.org> Date: Mon May 27 23:36:21 2019 +0200 patch 8.1.1413: error when the drive of the swap file was disconnected Problem: Error when the drive of the swap file was disconnected. Solution: Try closing and re-opening the swap file. (closes https://github.com/vim/vim/issues/4378)
author Bram Moolenaar <Bram@vim.org>
date Mon, 27 May 2019 23:45:04 +0200
parents ef00b6bc186b
children ce04ebdf26b8
line wrap: on
line diff
--- a/src/memfile.c
+++ b/src/memfile.c
@@ -994,7 +994,8 @@ mf_write(memfile_T *mfp, bhdr_T *hp)
     unsigned	page_count; /* number of pages written */
     unsigned	size;	    /* number of bytes written */
 
-    if (mfp->mf_fd < 0)	    /* there is no file, can't write */
+    if (mfp->mf_fd < 0 && !mfp->mf_reopen)
+	// there is no file and there was no file, can't write
 	return FAIL;
 
     if (hp->bh_bnum < 0)	/* must assign file block number */
@@ -1011,6 +1012,8 @@ mf_write(memfile_T *mfp, bhdr_T *hp)
      */
     for (;;)
     {
+	int attempt;
+
 	nr = hp->bh_bnum;
 	if (nr > mfp->mf_infile_count)		/* beyond end of file */
 	{
@@ -1021,29 +1024,49 @@ mf_write(memfile_T *mfp, bhdr_T *hp)
 	    hp2 = hp;
 
 	offset = (off_T)page_size * nr;
-	if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
-	{
-	    PERROR(_("E296: Seek error in swap file write"));
-	    return FAIL;
-	}
 	if (hp2 == NULL)	    /* freed block, fill with dummy data */
 	    page_count = 1;
 	else
 	    page_count = hp2->bh_page_count;
 	size = page_size * page_count;
-	if (mf_write_block(mfp, hp2 == NULL ? hp : hp2, offset, size) == FAIL)
+
+	for (attempt = 1; attempt <= 2; ++attempt)
 	{
-	    /*
-	     * Avoid repeating the error message, this mostly happens when the
-	     * disk is full. We give the message again only after a successful
-	     * write or when hitting a key. We keep on trying, in case some
-	     * space becomes available.
-	     */
-	    if (!did_swapwrite_msg)
-		emsg(_("E297: Write error in swap file"));
-	    did_swapwrite_msg = TRUE;
-	    return FAIL;
+	    if (mfp->mf_fd >= 0)
+	    {
+		if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
+		{
+		    PERROR(_("E296: Seek error in swap file write"));
+		    return FAIL;
+		}
+		if (mf_write_block(mfp,
+				   hp2 == NULL ? hp : hp2, offset, size) == OK)
+		    break;
+	    }
+
+	    if (attempt == 1)
+	    {
+		// If the swap file is on a network drive, and the network
+		// gets disconnected and then re-connected, we can maybe fix it
+		// by closing and then re-opening the file.
+		if (mfp->mf_fd >= 0)
+		    close(mfp->mf_fd);
+		mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, mfp->mf_flags);
+		mfp->mf_reopen = (mfp->mf_fd < 0);
+	    }
+	    if (attempt == 2 || mfp->mf_fd < 0)
+	    {
+		// Avoid repeating the error message, this mostly happens when
+		// the disk is full. We give the message again only after a
+		// successful write or when hitting a key. We keep on trying,
+		// in case some space becomes available.
+		if (!did_swapwrite_msg)
+		    emsg(_("E297: Write error in swap file"));
+		did_swapwrite_msg = TRUE;
+		return FAIL;
+	    }
 	}
+
 	did_swapwrite_msg = FALSE;
 	if (hp2 != NULL)		    /* written a non-dummy block */
 	    hp2->bh_flags &= ~BH_DIRTY;
@@ -1271,6 +1294,7 @@ mf_do_open(
 	 * the file) */
 	flags |= O_NOINHERIT;
 #endif
+	mfp->mf_flags = flags;
 	mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, flags);
     }